xref: /linux/drivers/scsi/ibmvscsi/ibmvfc-core.c (revision 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72)
1848c7085STyrel Datwyler /* SPDX-License-Identifier: GPL-2.0-or-later */
2848c7085STyrel Datwyler 
3848c7085STyrel Datwyler /*
4848c7085STyrel Datwyler  * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter
5848c7085STyrel Datwyler  *
6848c7085STyrel Datwyler  * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation
7848c7085STyrel Datwyler  *
8848c7085STyrel Datwyler  * Copyright (C) IBM Corporation, 2008-2026
9848c7085STyrel Datwyler  */
10848c7085STyrel Datwyler 
11848c7085STyrel Datwyler #include <linux/module.h>
12848c7085STyrel Datwyler #include <linux/moduleparam.h>
13848c7085STyrel Datwyler #include <linux/dma-mapping.h>
14848c7085STyrel Datwyler #include <linux/dmapool.h>
15848c7085STyrel Datwyler #include <linux/delay.h>
16848c7085STyrel Datwyler #include <linux/interrupt.h>
17848c7085STyrel Datwyler #include <linux/irqdomain.h>
18848c7085STyrel Datwyler #include <linux/kthread.h>
19848c7085STyrel Datwyler #include <linux/slab.h>
20848c7085STyrel Datwyler #include <linux/of.h>
21848c7085STyrel Datwyler #include <linux/pm.h>
22848c7085STyrel Datwyler #include <linux/stringify.h>
23848c7085STyrel Datwyler #include <linux/bsg-lib.h>
24848c7085STyrel Datwyler #include <asm/firmware.h>
25848c7085STyrel Datwyler #include <asm/irq.h>
26848c7085STyrel Datwyler #include <asm/vio.h>
27848c7085STyrel Datwyler #include <scsi/scsi.h>
28848c7085STyrel Datwyler #include <scsi/scsi_cmnd.h>
29848c7085STyrel Datwyler #include <scsi/scsi_host.h>
30848c7085STyrel Datwyler #include <scsi/scsi_device.h>
31848c7085STyrel Datwyler #include <scsi/scsi_tcq.h>
32848c7085STyrel Datwyler #include <scsi/scsi_transport_fc.h>
33848c7085STyrel Datwyler #include <scsi/scsi_bsg_fc.h>
34848c7085STyrel Datwyler #include "ibmvfc.h"
35848c7085STyrel Datwyler 
36848c7085STyrel Datwyler static unsigned int init_timeout = IBMVFC_INIT_TIMEOUT;
37848c7085STyrel Datwyler static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT;
38848c7085STyrel Datwyler static u64 max_lun = IBMVFC_MAX_LUN;
39848c7085STyrel Datwyler static unsigned int max_targets = IBMVFC_MAX_TARGETS;
40848c7085STyrel Datwyler static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT;
41848c7085STyrel Datwyler static u16 max_sectors = IBMVFC_MAX_SECTORS;
42848c7085STyrel Datwyler static u16 scsi_qdepth = IBMVFC_SCSI_QDEPTH;
43848c7085STyrel Datwyler static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS;
44848c7085STyrel Datwyler static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL;
45848c7085STyrel Datwyler static unsigned int cls3_error = IBMVFC_CLS3_ERROR;
46848c7085STyrel Datwyler static unsigned int mq_enabled = IBMVFC_MQ;
47848c7085STyrel Datwyler static unsigned int nr_scsi_hw_queues = IBMVFC_SCSI_HW_QUEUES;
48848c7085STyrel Datwyler static unsigned int nr_scsi_channels = IBMVFC_SCSI_CHANNELS;
49848c7085STyrel Datwyler static unsigned int nvme_enabled = IBMVFC_NVME;
50848c7085STyrel Datwyler static unsigned int nr_nvme_hw_queues = IBMVFC_NVME_HW_QUEUES;
51848c7085STyrel Datwyler static unsigned int nr_nvme_channels = IBMVFC_NVME_CHANNELS;
52848c7085STyrel Datwyler static unsigned int mig_channels_only = IBMVFC_MIG_NO_SUB_TO_CRQ;
53848c7085STyrel Datwyler static unsigned int mig_no_less_channels = IBMVFC_MIG_NO_N_TO_M;
54848c7085STyrel Datwyler 
5528ec8670STyrel Datwyler unsigned int ibmvfc_debug = IBMVFC_DEBUG;
5628ec8670STyrel Datwyler 
57848c7085STyrel Datwyler static LIST_HEAD(ibmvfc_head);
58848c7085STyrel Datwyler static DEFINE_SPINLOCK(ibmvfc_driver_lock);
59848c7085STyrel Datwyler static struct scsi_transport_template *ibmvfc_transport_template;
60848c7085STyrel Datwyler 
61848c7085STyrel Datwyler MODULE_DESCRIPTION("IBM Virtual Fibre Channel Driver");
62848c7085STyrel Datwyler MODULE_AUTHOR("Brian King <brking@linux.vnet.ibm.com>");
63848c7085STyrel Datwyler MODULE_LICENSE("GPL");
64848c7085STyrel Datwyler MODULE_VERSION(IBMVFC_DRIVER_VERSION);
65848c7085STyrel Datwyler 
66848c7085STyrel Datwyler module_param_named(mq, mq_enabled, uint, S_IRUGO);
67848c7085STyrel Datwyler MODULE_PARM_DESC(mq, "Enable multiqueue support. "
68848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MQ) "]");
69848c7085STyrel Datwyler module_param_named(scsi_host_queues, nr_scsi_hw_queues, uint, S_IRUGO);
70848c7085STyrel Datwyler MODULE_PARM_DESC(scsi_host_queues, "Number of SCSI Host submission queues. "
71848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_SCSI_HW_QUEUES) "]");
72848c7085STyrel Datwyler module_param_named(scsi_hw_channels, nr_scsi_channels, uint, S_IRUGO);
73848c7085STyrel Datwyler MODULE_PARM_DESC(scsi_hw_channels, "Number of hw scsi channels to request. "
74848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_SCSI_CHANNELS) "]");
75848c7085STyrel Datwyler module_param_named(mig_channels_only, mig_channels_only, uint, S_IRUGO);
76848c7085STyrel Datwyler MODULE_PARM_DESC(mig_channels_only, "Prevent migration to non-channelized system. "
77848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MIG_NO_SUB_TO_CRQ) "]");
78848c7085STyrel Datwyler module_param_named(mig_no_less_channels, mig_no_less_channels, uint, S_IRUGO);
79848c7085STyrel Datwyler MODULE_PARM_DESC(mig_no_less_channels, "Prevent migration to system with less channels. "
80848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MIG_NO_N_TO_M) "]");
81848c7085STyrel Datwyler 
82848c7085STyrel Datwyler module_param_named(nvme, nvme_enabled, uint, S_IRUGO);
83848c7085STyrel Datwyler MODULE_PARM_DESC(nvme, "Enable NVMe over FC support. "
84848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_NVME) "]");
85848c7085STyrel Datwyler module_param_named(nvme_host_queues, nr_nvme_hw_queues, uint, S_IRUGO);
86848c7085STyrel Datwyler MODULE_PARM_DESC(nvme_host_queues, "Number of NVMeoF Host submission queues. "
87848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_NVME_HW_QUEUES) "]");
88848c7085STyrel Datwyler module_param_named(nvme_hw_channels, nr_nvme_channels, uint, S_IRUGO);
89848c7085STyrel Datwyler MODULE_PARM_DESC(nvme_hw_channels, "Number of hw NVMeoF channels to request. "
90848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_NVME_CHANNELS) "]");
91848c7085STyrel Datwyler 
92848c7085STyrel Datwyler module_param_named(init_timeout, init_timeout, uint, S_IRUGO | S_IWUSR);
93848c7085STyrel Datwyler MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds. "
94848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_INIT_TIMEOUT) "]");
95848c7085STyrel Datwyler module_param_named(default_timeout, default_timeout, uint, S_IRUGO | S_IWUSR);
96848c7085STyrel Datwyler MODULE_PARM_DESC(default_timeout,
97848c7085STyrel Datwyler 		 "Default timeout in seconds for initialization and EH commands. "
98848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_DEFAULT_TIMEOUT) "]");
99848c7085STyrel Datwyler module_param_named(max_requests, max_requests, uint, S_IRUGO);
100848c7085STyrel Datwyler MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. "
101848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]");
102848c7085STyrel Datwyler module_param_named(max_sectors, max_sectors, ushort, S_IRUGO);
103848c7085STyrel Datwyler MODULE_PARM_DESC(max_sectors, "Maximum sectors for this adapter. "
104848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MAX_SECTORS) "]");
105848c7085STyrel Datwyler module_param_named(scsi_qdepth, scsi_qdepth, ushort, S_IRUGO);
106848c7085STyrel Datwyler MODULE_PARM_DESC(scsi_qdepth, "Maximum scsi command depth per adapter queue. "
107848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_SCSI_QDEPTH) "]");
108848c7085STyrel Datwyler module_param_named(max_lun, max_lun, ullong, S_IRUGO);
109848c7085STyrel Datwyler MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. "
110848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MAX_LUN) "]");
111848c7085STyrel Datwyler module_param_named(max_targets, max_targets, uint, S_IRUGO);
112848c7085STyrel Datwyler MODULE_PARM_DESC(max_targets, "Maximum allowed targets. "
113848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MAX_TARGETS) "]");
114848c7085STyrel Datwyler module_param_named(disc_threads, disc_threads, uint, S_IRUGO);
115848c7085STyrel Datwyler MODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. "
116848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_MAX_DISC_THREADS) "]");
117848c7085STyrel Datwyler module_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR);
118848c7085STyrel Datwyler MODULE_PARM_DESC(debug, "Enable driver debug information. "
119848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_DEBUG) "]");
120848c7085STyrel Datwyler module_param_named(log_level, log_level, uint, 0);
121848c7085STyrel Datwyler MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. "
122848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]");
123848c7085STyrel Datwyler module_param_named(cls3_error, cls3_error, uint, 0);
124848c7085STyrel Datwyler MODULE_PARM_DESC(cls3_error, "Enable FC Class 3 Error Recovery. "
125848c7085STyrel Datwyler 		 "[Default=" __stringify(IBMVFC_CLS3_ERROR) "]");
126848c7085STyrel Datwyler 
127848c7085STyrel Datwyler static const struct {
128848c7085STyrel Datwyler 	u16 status;
129848c7085STyrel Datwyler 	u16 error;
130848c7085STyrel Datwyler 	u8 result;
131848c7085STyrel Datwyler 	u8 retry;
132848c7085STyrel Datwyler 	int log;
133848c7085STyrel Datwyler 	char *name;
134848c7085STyrel Datwyler } cmd_status [] = {
135848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" },
136848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" },
137848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" },
138848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" },
139848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" },
140848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" },
141848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" },
142848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_REGISTER, DID_ERROR, 1, 1, "unable to register" },
143848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_BUSY, DID_BUS_BUSY, 1, 0, "transport busy" },
144848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" },
145848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" },
146848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" },
147848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 1, 0, "link halted" },
148848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" },
149848c7085STyrel Datwyler 
150848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" },
151848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" },
152848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" },
153848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" },
154848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" },
155848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" },
156848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 0, 1, "transaction cancelled implicit" },
157848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" },
158848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" },
159848c7085STyrel Datwyler 	{ IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" },
160848c7085STyrel Datwyler 
161848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" },
162848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_INVALID_VERSION, DID_ERROR, 0, 1, "invalid version level" },
163848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_ERROR, DID_ERROR, 1, 1, "logical error" },
164848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_INVALID_CT_IU_SIZE, DID_ERROR, 0, 1, "invalid CT_IU size" },
165848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_BUSY, DID_REQUEUE, 1, 0, "logical busy" },
166848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_PROTOCOL_ERROR, DID_ERROR, 1, 1, "protocol error" },
167848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_UNABLE_TO_PERFORM_REQ, DID_ERROR, 1, 1, "unable to perform request" },
168848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_CMD_NOT_SUPPORTED, DID_ERROR, 0, 0, "command not supported" },
169848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_SERVER_NOT_AVAIL, DID_ERROR, 0, 1, "server not available" },
170848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_CMD_IN_PROGRESS, DID_ERROR, 0, 1, "command already in progress" },
171848c7085STyrel Datwyler 	{ IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" },
172848c7085STyrel Datwyler 
173848c7085STyrel Datwyler 	{ IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" },
174848c7085STyrel Datwyler 	{ IBMVFC_FC_SCSI_ERROR, IBMVFC_COMMAND_FAILED, DID_ERROR, 0, 1, "PRLI to device failed." },
175848c7085STyrel Datwyler };
176848c7085STyrel Datwyler 
1775e9dd037STyrel Datwyler static const char *proto_type[] = {
1785e9dd037STyrel Datwyler 	"SCSI",
1795e9dd037STyrel Datwyler 	"NVMe",
1805e9dd037STyrel Datwyler };
1815e9dd037STyrel Datwyler 
182848c7085STyrel Datwyler static void ibmvfc_npiv_login(struct ibmvfc_host *);
183848c7085STyrel Datwyler static void ibmvfc_tgt_send_prli(struct ibmvfc_target *);
184848c7085STyrel Datwyler static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *);
185848c7085STyrel Datwyler static void ibmvfc_tgt_query_target(struct ibmvfc_target *);
186848c7085STyrel Datwyler static void ibmvfc_npiv_logout(struct ibmvfc_host *);
187848c7085STyrel Datwyler static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *);
188848c7085STyrel Datwyler static void ibmvfc_tgt_move_login(struct ibmvfc_target *);
189848c7085STyrel Datwyler 
190848c7085STyrel Datwyler static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *, struct ibmvfc_channels *);
191848c7085STyrel Datwyler static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *, struct ibmvfc_channels *);
192848c7085STyrel Datwyler 
193848c7085STyrel Datwyler static const char *unknown_error = "unknown error";
194848c7085STyrel Datwyler 
h_reg_sub_crq(unsigned long unit_address,unsigned long ioba,unsigned long length,unsigned long * cookie,unsigned long * irq)195848c7085STyrel Datwyler static long h_reg_sub_crq(unsigned long unit_address, unsigned long ioba,
196848c7085STyrel Datwyler 			  unsigned long length, unsigned long *cookie,
197848c7085STyrel Datwyler 			  unsigned long *irq)
198848c7085STyrel Datwyler {
199848c7085STyrel Datwyler 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
200848c7085STyrel Datwyler 	long rc;
201848c7085STyrel Datwyler 
202848c7085STyrel Datwyler 	rc = plpar_hcall(H_REG_SUB_CRQ, retbuf, unit_address, ioba, length);
203848c7085STyrel Datwyler 	*cookie = retbuf[0];
204848c7085STyrel Datwyler 	*irq = retbuf[1];
205848c7085STyrel Datwyler 
206848c7085STyrel Datwyler 	return rc;
207848c7085STyrel Datwyler }
208848c7085STyrel Datwyler 
ibmvfc_nvme_active(struct ibmvfc_host * vhost)2098acacfa8STyrel Datwyler static int ibmvfc_nvme_active(struct ibmvfc_host *vhost)
2108acacfa8STyrel Datwyler {
2118acacfa8STyrel Datwyler 	return (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NVMEOF) &&
2128acacfa8STyrel Datwyler 		vhost->nvme_scrqs.active_queues);
2138acacfa8STyrel Datwyler }
2148acacfa8STyrel Datwyler 
ibmvfc_get_fcp_iu(struct ibmvfc_host * vhost,struct ibmvfc_cmd * vfc_cmd)215848c7085STyrel Datwyler static struct ibmvfc_fcp_cmd_iu *ibmvfc_get_fcp_iu(struct ibmvfc_host *vhost,
216848c7085STyrel Datwyler 						   struct ibmvfc_cmd *vfc_cmd)
217848c7085STyrel Datwyler {
218ecc03d95STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NVMEOF))
219ecc03d95STyrel Datwyler 		return &vfc_cmd->v3scsi.iu;
220ecc03d95STyrel Datwyler 	else if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN))
221848c7085STyrel Datwyler 		return &vfc_cmd->v2.iu;
222848c7085STyrel Datwyler 	else
223848c7085STyrel Datwyler 		return &vfc_cmd->v1.iu;
224848c7085STyrel Datwyler }
225848c7085STyrel Datwyler 
ibmvfc_get_fcp_rsp(struct ibmvfc_host * vhost,struct ibmvfc_cmd * vfc_cmd)226848c7085STyrel Datwyler static struct ibmvfc_fcp_rsp *ibmvfc_get_fcp_rsp(struct ibmvfc_host *vhost,
227848c7085STyrel Datwyler 						 struct ibmvfc_cmd *vfc_cmd)
228848c7085STyrel Datwyler {
229ecc03d95STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NVMEOF))
230ecc03d95STyrel Datwyler 		return &vfc_cmd->v3scsi.rsp;
231ecc03d95STyrel Datwyler 	else if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN))
232848c7085STyrel Datwyler 		return &vfc_cmd->v2.rsp;
233848c7085STyrel Datwyler 	else
234848c7085STyrel Datwyler 		return &vfc_cmd->v1.rsp;
235848c7085STyrel Datwyler }
236848c7085STyrel Datwyler 
237848c7085STyrel Datwyler #ifdef CONFIG_SCSI_IBMVFC_TRACE
238848c7085STyrel Datwyler /**
239848c7085STyrel Datwyler  * ibmvfc_trc_start - Log a start trace entry
240848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
241848c7085STyrel Datwyler  *
242848c7085STyrel Datwyler  **/
ibmvfc_trc_start(struct ibmvfc_event * evt)243848c7085STyrel Datwyler static void ibmvfc_trc_start(struct ibmvfc_event *evt)
244848c7085STyrel Datwyler {
245848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
246848c7085STyrel Datwyler 	struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd;
247848c7085STyrel Datwyler 	struct ibmvfc_mad_common *mad = &evt->iu.mad_common;
248848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd);
249848c7085STyrel Datwyler 	struct ibmvfc_trace_entry *entry;
250848c7085STyrel Datwyler 	int index = atomic_inc_return(&vhost->trace_index) & IBMVFC_TRACE_INDEX_MASK;
251848c7085STyrel Datwyler 
252848c7085STyrel Datwyler 	entry = &vhost->trace[index];
253848c7085STyrel Datwyler 	entry->evt = evt;
254848c7085STyrel Datwyler 	entry->time = jiffies;
255848c7085STyrel Datwyler 	entry->fmt = evt->crq.format;
256848c7085STyrel Datwyler 	entry->type = IBMVFC_TRC_START;
257848c7085STyrel Datwyler 
258848c7085STyrel Datwyler 	switch (entry->fmt) {
259848c7085STyrel Datwyler 	case IBMVFC_CMD_FORMAT:
260848c7085STyrel Datwyler 		entry->op_code = iu->cdb[0];
261848c7085STyrel Datwyler 		entry->scsi_id = be64_to_cpu(vfc_cmd->tgt_scsi_id);
262848c7085STyrel Datwyler 		entry->lun = scsilun_to_int(&iu->lun);
263848c7085STyrel Datwyler 		entry->tmf_flags = iu->tmf_flags;
264848c7085STyrel Datwyler 		entry->u.start.xfer_len = be32_to_cpu(iu->xfer_len);
265848c7085STyrel Datwyler 		break;
266848c7085STyrel Datwyler 	case IBMVFC_MAD_FORMAT:
267848c7085STyrel Datwyler 		entry->op_code = be32_to_cpu(mad->opcode);
268848c7085STyrel Datwyler 		break;
269848c7085STyrel Datwyler 	default:
270848c7085STyrel Datwyler 		break;
271848c7085STyrel Datwyler 	}
272848c7085STyrel Datwyler }
273848c7085STyrel Datwyler 
274848c7085STyrel Datwyler /**
275848c7085STyrel Datwyler  * ibmvfc_trc_end - Log an end trace entry
276848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
277848c7085STyrel Datwyler  *
278848c7085STyrel Datwyler  **/
ibmvfc_trc_end(struct ibmvfc_event * evt)279848c7085STyrel Datwyler static void ibmvfc_trc_end(struct ibmvfc_event *evt)
280848c7085STyrel Datwyler {
281848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
282848c7085STyrel Datwyler 	struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd;
283848c7085STyrel Datwyler 	struct ibmvfc_mad_common *mad = &evt->xfer_iu->mad_common;
284848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd);
285848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd);
286848c7085STyrel Datwyler 	struct ibmvfc_trace_entry *entry;
287848c7085STyrel Datwyler 	int index = atomic_inc_return(&vhost->trace_index) & IBMVFC_TRACE_INDEX_MASK;
288848c7085STyrel Datwyler 
289848c7085STyrel Datwyler 	entry = &vhost->trace[index];
290848c7085STyrel Datwyler 	entry->evt = evt;
291848c7085STyrel Datwyler 	entry->time = jiffies;
292848c7085STyrel Datwyler 	entry->fmt = evt->crq.format;
293848c7085STyrel Datwyler 	entry->type = IBMVFC_TRC_END;
294848c7085STyrel Datwyler 
295848c7085STyrel Datwyler 	switch (entry->fmt) {
296848c7085STyrel Datwyler 	case IBMVFC_CMD_FORMAT:
297848c7085STyrel Datwyler 		entry->op_code = iu->cdb[0];
298848c7085STyrel Datwyler 		entry->scsi_id = be64_to_cpu(vfc_cmd->tgt_scsi_id);
299848c7085STyrel Datwyler 		entry->lun = scsilun_to_int(&iu->lun);
300848c7085STyrel Datwyler 		entry->tmf_flags = iu->tmf_flags;
301848c7085STyrel Datwyler 		entry->u.end.status = be16_to_cpu(vfc_cmd->status);
302848c7085STyrel Datwyler 		entry->u.end.error = be16_to_cpu(vfc_cmd->error);
303848c7085STyrel Datwyler 		entry->u.end.fcp_rsp_flags = rsp->flags;
304848c7085STyrel Datwyler 		entry->u.end.rsp_code = rsp->data.info.rsp_code;
305848c7085STyrel Datwyler 		entry->u.end.scsi_status = rsp->scsi_status;
306848c7085STyrel Datwyler 		break;
307848c7085STyrel Datwyler 	case IBMVFC_MAD_FORMAT:
308848c7085STyrel Datwyler 		entry->op_code = be32_to_cpu(mad->opcode);
309848c7085STyrel Datwyler 		entry->u.end.status = be16_to_cpu(mad->status);
310848c7085STyrel Datwyler 		break;
311848c7085STyrel Datwyler 	default:
312848c7085STyrel Datwyler 		break;
313848c7085STyrel Datwyler 
314848c7085STyrel Datwyler 	}
315848c7085STyrel Datwyler }
316848c7085STyrel Datwyler 
317848c7085STyrel Datwyler #else
318848c7085STyrel Datwyler #define ibmvfc_trc_start(evt) do { } while (0)
319848c7085STyrel Datwyler #define ibmvfc_trc_end(evt) do { } while (0)
320848c7085STyrel Datwyler #endif
321848c7085STyrel Datwyler 
322848c7085STyrel Datwyler /**
323848c7085STyrel Datwyler  * ibmvfc_get_err_index - Find the index into cmd_status for the fcp response
324848c7085STyrel Datwyler  * @status:		status / error class
325848c7085STyrel Datwyler  * @error:		error
326848c7085STyrel Datwyler  *
327848c7085STyrel Datwyler  * Return value:
328848c7085STyrel Datwyler  *	index into cmd_status / -EINVAL on failure
329848c7085STyrel Datwyler  **/
ibmvfc_get_err_index(u16 status,u16 error)330848c7085STyrel Datwyler static int ibmvfc_get_err_index(u16 status, u16 error)
331848c7085STyrel Datwyler {
332848c7085STyrel Datwyler 	int i;
333848c7085STyrel Datwyler 
334848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(cmd_status); i++)
335848c7085STyrel Datwyler 		if ((cmd_status[i].status & status) == cmd_status[i].status &&
336848c7085STyrel Datwyler 		    cmd_status[i].error == error)
337848c7085STyrel Datwyler 			return i;
338848c7085STyrel Datwyler 
339848c7085STyrel Datwyler 	return -EINVAL;
340848c7085STyrel Datwyler }
341848c7085STyrel Datwyler 
342848c7085STyrel Datwyler /**
343848c7085STyrel Datwyler  * ibmvfc_get_cmd_error - Find the error description for the fcp response
344848c7085STyrel Datwyler  * @status:		status / error class
345848c7085STyrel Datwyler  * @error:		error
346848c7085STyrel Datwyler  *
347848c7085STyrel Datwyler  * Return value:
348848c7085STyrel Datwyler  *	error description string
349848c7085STyrel Datwyler  **/
ibmvfc_get_cmd_error(u16 status,u16 error)3506fac8df9STyrel Datwyler const char *ibmvfc_get_cmd_error(u16 status, u16 error)
351848c7085STyrel Datwyler {
352848c7085STyrel Datwyler 	int rc = ibmvfc_get_err_index(status, error);
353848c7085STyrel Datwyler 	if (rc >= 0)
354848c7085STyrel Datwyler 		return cmd_status[rc].name;
355848c7085STyrel Datwyler 	return unknown_error;
356848c7085STyrel Datwyler }
357848c7085STyrel Datwyler 
358848c7085STyrel Datwyler /**
359848c7085STyrel Datwyler  * ibmvfc_get_err_result - Find the scsi status to return for the fcp response
360848c7085STyrel Datwyler  * @vhost:      ibmvfc host struct
361848c7085STyrel Datwyler  * @vfc_cmd:	ibmvfc command struct
362848c7085STyrel Datwyler  *
363848c7085STyrel Datwyler  * Return value:
364848c7085STyrel Datwyler  *	SCSI result value to return for completed command
365848c7085STyrel Datwyler  **/
ibmvfc_get_err_result(struct ibmvfc_host * vhost,struct ibmvfc_cmd * vfc_cmd)366848c7085STyrel Datwyler static int ibmvfc_get_err_result(struct ibmvfc_host *vhost, struct ibmvfc_cmd *vfc_cmd)
367848c7085STyrel Datwyler {
368848c7085STyrel Datwyler 	int err;
369848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd);
370848c7085STyrel Datwyler 	int fc_rsp_len = be32_to_cpu(rsp->fcp_rsp_len);
371848c7085STyrel Datwyler 
372848c7085STyrel Datwyler 	if ((rsp->flags & FCP_RSP_LEN_VALID) &&
373848c7085STyrel Datwyler 	    ((fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) ||
374848c7085STyrel Datwyler 	     rsp->data.info.rsp_code))
375848c7085STyrel Datwyler 		return DID_ERROR << 16;
376848c7085STyrel Datwyler 
377848c7085STyrel Datwyler 	err = ibmvfc_get_err_index(be16_to_cpu(vfc_cmd->status), be16_to_cpu(vfc_cmd->error));
378848c7085STyrel Datwyler 	if (err >= 0)
379848c7085STyrel Datwyler 		return rsp->scsi_status | (cmd_status[err].result << 16);
380848c7085STyrel Datwyler 	return rsp->scsi_status | (DID_ERROR << 16);
381848c7085STyrel Datwyler }
382848c7085STyrel Datwyler 
383848c7085STyrel Datwyler /**
384848c7085STyrel Datwyler  * ibmvfc_retry_cmd - Determine if error status is retryable
385848c7085STyrel Datwyler  * @status:		status / error class
386848c7085STyrel Datwyler  * @error:		error
387848c7085STyrel Datwyler  *
388848c7085STyrel Datwyler  * Return value:
389848c7085STyrel Datwyler  *	1 if error should be retried / 0 if it should not
390848c7085STyrel Datwyler  **/
ibmvfc_retry_cmd(u16 status,u16 error)391848c7085STyrel Datwyler static int ibmvfc_retry_cmd(u16 status, u16 error)
392848c7085STyrel Datwyler {
393848c7085STyrel Datwyler 	int rc = ibmvfc_get_err_index(status, error);
394848c7085STyrel Datwyler 
395848c7085STyrel Datwyler 	if (rc >= 0)
396848c7085STyrel Datwyler 		return cmd_status[rc].retry;
397848c7085STyrel Datwyler 	return 1;
398848c7085STyrel Datwyler }
399848c7085STyrel Datwyler 
400848c7085STyrel Datwyler static const char *unknown_fc_explain = "unknown fc explain";
401848c7085STyrel Datwyler 
402848c7085STyrel Datwyler static const struct {
403848c7085STyrel Datwyler 	u16 fc_explain;
404848c7085STyrel Datwyler 	char *name;
405848c7085STyrel Datwyler } ls_explain [] = {
406848c7085STyrel Datwyler 	{ 0x00, "no additional explanation" },
407848c7085STyrel Datwyler 	{ 0x01, "service parameter error - options" },
408848c7085STyrel Datwyler 	{ 0x03, "service parameter error - initiator control" },
409848c7085STyrel Datwyler 	{ 0x05, "service parameter error - recipient control" },
410848c7085STyrel Datwyler 	{ 0x07, "service parameter error - received data field size" },
411848c7085STyrel Datwyler 	{ 0x09, "service parameter error - concurrent seq" },
412848c7085STyrel Datwyler 	{ 0x0B, "service parameter error - credit" },
413848c7085STyrel Datwyler 	{ 0x0D, "invalid N_Port/F_Port_Name" },
414848c7085STyrel Datwyler 	{ 0x0E, "invalid node/Fabric Name" },
415848c7085STyrel Datwyler 	{ 0x0F, "invalid common service parameters" },
416848c7085STyrel Datwyler 	{ 0x11, "invalid association header" },
417848c7085STyrel Datwyler 	{ 0x13, "association header required" },
418848c7085STyrel Datwyler 	{ 0x15, "invalid originator S_ID" },
419848c7085STyrel Datwyler 	{ 0x17, "invalid OX_ID-RX-ID combination" },
420848c7085STyrel Datwyler 	{ 0x19, "command (request) already in progress" },
421848c7085STyrel Datwyler 	{ 0x1E, "N_Port Login requested" },
422848c7085STyrel Datwyler 	{ 0x1F, "Invalid N_Port_ID" },
423848c7085STyrel Datwyler };
424848c7085STyrel Datwyler 
425848c7085STyrel Datwyler static const struct {
426848c7085STyrel Datwyler 	u16 fc_explain;
427848c7085STyrel Datwyler 	char *name;
428848c7085STyrel Datwyler } gs_explain [] = {
429848c7085STyrel Datwyler 	{ 0x00, "no additional explanation" },
430848c7085STyrel Datwyler 	{ 0x01, "port identifier not registered" },
431848c7085STyrel Datwyler 	{ 0x02, "port name not registered" },
432848c7085STyrel Datwyler 	{ 0x03, "node name not registered" },
433848c7085STyrel Datwyler 	{ 0x04, "class of service not registered" },
434848c7085STyrel Datwyler 	{ 0x06, "initial process associator not registered" },
435848c7085STyrel Datwyler 	{ 0x07, "FC-4 TYPEs not registered" },
436848c7085STyrel Datwyler 	{ 0x08, "symbolic port name not registered" },
437848c7085STyrel Datwyler 	{ 0x09, "symbolic node name not registered" },
438848c7085STyrel Datwyler 	{ 0x0A, "port type not registered" },
439848c7085STyrel Datwyler 	{ 0xF0, "authorization exception" },
440848c7085STyrel Datwyler 	{ 0xF1, "authentication exception" },
441848c7085STyrel Datwyler 	{ 0xF2, "data base full" },
442848c7085STyrel Datwyler 	{ 0xF3, "data base empty" },
443848c7085STyrel Datwyler 	{ 0xF4, "processing request" },
444848c7085STyrel Datwyler 	{ 0xF5, "unable to verify connection" },
445848c7085STyrel Datwyler 	{ 0xF6, "devices not in a common zone" },
446848c7085STyrel Datwyler };
447848c7085STyrel Datwyler 
448848c7085STyrel Datwyler /**
449848c7085STyrel Datwyler  * ibmvfc_get_ls_explain - Return the FC Explain description text
450848c7085STyrel Datwyler  * @status:	FC Explain status
451848c7085STyrel Datwyler  *
452848c7085STyrel Datwyler  * Returns:
453848c7085STyrel Datwyler  *	error string
454848c7085STyrel Datwyler  **/
ibmvfc_get_ls_explain(u16 status)455848c7085STyrel Datwyler static const char *ibmvfc_get_ls_explain(u16 status)
456848c7085STyrel Datwyler {
457848c7085STyrel Datwyler 	int i;
458848c7085STyrel Datwyler 
459848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(ls_explain); i++)
460848c7085STyrel Datwyler 		if (ls_explain[i].fc_explain == status)
461848c7085STyrel Datwyler 			return ls_explain[i].name;
462848c7085STyrel Datwyler 
463848c7085STyrel Datwyler 	return unknown_fc_explain;
464848c7085STyrel Datwyler }
465848c7085STyrel Datwyler 
466848c7085STyrel Datwyler /**
467848c7085STyrel Datwyler  * ibmvfc_get_gs_explain - Return the FC Explain description text
468848c7085STyrel Datwyler  * @status:	FC Explain status
469848c7085STyrel Datwyler  *
470848c7085STyrel Datwyler  * Returns:
471848c7085STyrel Datwyler  *	error string
472848c7085STyrel Datwyler  **/
ibmvfc_get_gs_explain(u16 status)473848c7085STyrel Datwyler static const char *ibmvfc_get_gs_explain(u16 status)
474848c7085STyrel Datwyler {
475848c7085STyrel Datwyler 	int i;
476848c7085STyrel Datwyler 
477848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(gs_explain); i++)
478848c7085STyrel Datwyler 		if (gs_explain[i].fc_explain == status)
479848c7085STyrel Datwyler 			return gs_explain[i].name;
480848c7085STyrel Datwyler 
481848c7085STyrel Datwyler 	return unknown_fc_explain;
482848c7085STyrel Datwyler }
483848c7085STyrel Datwyler 
484848c7085STyrel Datwyler static const struct {
485848c7085STyrel Datwyler 	enum ibmvfc_fc_type fc_type;
486848c7085STyrel Datwyler 	char *name;
487848c7085STyrel Datwyler } fc_type [] = {
488848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_REJECT, "fabric reject" },
489848c7085STyrel Datwyler 	{ IBMVFC_PORT_REJECT, "port reject" },
490848c7085STyrel Datwyler 	{ IBMVFC_LS_REJECT, "ELS reject" },
491848c7085STyrel Datwyler 	{ IBMVFC_FABRIC_BUSY, "fabric busy" },
492848c7085STyrel Datwyler 	{ IBMVFC_PORT_BUSY, "port busy" },
493848c7085STyrel Datwyler 	{ IBMVFC_BASIC_REJECT, "basic reject" },
494848c7085STyrel Datwyler 	{ IBMVFC_FC4_LS_REJECT, "fc4 ls reject" },
495848c7085STyrel Datwyler };
496848c7085STyrel Datwyler 
497848c7085STyrel Datwyler static const char *unknown_fc_type = "unknown fc type";
498848c7085STyrel Datwyler 
499848c7085STyrel Datwyler /**
500848c7085STyrel Datwyler  * ibmvfc_get_fc_type - Return the FC Type description text
501848c7085STyrel Datwyler  * @status:	FC Type error status
502848c7085STyrel Datwyler  *
503848c7085STyrel Datwyler  * Returns:
504848c7085STyrel Datwyler  *	error string
505848c7085STyrel Datwyler  **/
ibmvfc_get_fc_type(u16 status)506848c7085STyrel Datwyler static const char *ibmvfc_get_fc_type(u16 status)
507848c7085STyrel Datwyler {
508848c7085STyrel Datwyler 	int i;
509848c7085STyrel Datwyler 
510848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(fc_type); i++)
511848c7085STyrel Datwyler 		if (fc_type[i].fc_type == status)
512848c7085STyrel Datwyler 			return fc_type[i].name;
513848c7085STyrel Datwyler 
514848c7085STyrel Datwyler 	return unknown_fc_type;
515848c7085STyrel Datwyler }
516848c7085STyrel Datwyler 
517848c7085STyrel Datwyler /**
518848c7085STyrel Datwyler  * ibmvfc_set_tgt_action - Set the next init action for the target
519848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
520848c7085STyrel Datwyler  * @action:		action to perform
521848c7085STyrel Datwyler  *
522848c7085STyrel Datwyler  * Returns:
523848c7085STyrel Datwyler  *	0 if action changed / non-zero if not changed
524848c7085STyrel Datwyler  **/
ibmvfc_set_tgt_action(struct ibmvfc_target * tgt,enum ibmvfc_target_action action)525848c7085STyrel Datwyler static int ibmvfc_set_tgt_action(struct ibmvfc_target *tgt,
526848c7085STyrel Datwyler 				  enum ibmvfc_target_action action)
527848c7085STyrel Datwyler {
528848c7085STyrel Datwyler 	int rc = -EINVAL;
529848c7085STyrel Datwyler 
530848c7085STyrel Datwyler 	switch (tgt->action) {
531848c7085STyrel Datwyler 	case IBMVFC_TGT_ACTION_LOGOUT_RPORT:
532848c7085STyrel Datwyler 		if (action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT ||
533848c7085STyrel Datwyler 		    action == IBMVFC_TGT_ACTION_DEL_RPORT) {
534848c7085STyrel Datwyler 			tgt->action = action;
535848c7085STyrel Datwyler 			rc = 0;
536848c7085STyrel Datwyler 		}
537848c7085STyrel Datwyler 		break;
538848c7085STyrel Datwyler 	case IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT:
539848c7085STyrel Datwyler 		if (action == IBMVFC_TGT_ACTION_DEL_RPORT ||
540848c7085STyrel Datwyler 		    action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) {
541848c7085STyrel Datwyler 			tgt->action = action;
542848c7085STyrel Datwyler 			rc = 0;
543848c7085STyrel Datwyler 		}
544848c7085STyrel Datwyler 		break;
545848c7085STyrel Datwyler 	case IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT:
546848c7085STyrel Datwyler 		if (action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) {
547848c7085STyrel Datwyler 			tgt->action = action;
548848c7085STyrel Datwyler 			rc = 0;
549848c7085STyrel Datwyler 		}
550848c7085STyrel Datwyler 		break;
551848c7085STyrel Datwyler 	case IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT:
552848c7085STyrel Datwyler 		if (action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) {
553848c7085STyrel Datwyler 			tgt->action = action;
554848c7085STyrel Datwyler 			rc = 0;
555848c7085STyrel Datwyler 		}
556848c7085STyrel Datwyler 		break;
557848c7085STyrel Datwyler 	case IBMVFC_TGT_ACTION_DEL_RPORT:
558848c7085STyrel Datwyler 		if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) {
559848c7085STyrel Datwyler 			tgt->action = action;
560848c7085STyrel Datwyler 			rc = 0;
561848c7085STyrel Datwyler 		}
562848c7085STyrel Datwyler 		break;
563848c7085STyrel Datwyler 	case IBMVFC_TGT_ACTION_DELETED_RPORT:
564848c7085STyrel Datwyler 		break;
565848c7085STyrel Datwyler 	default:
566848c7085STyrel Datwyler 		tgt->action = action;
567848c7085STyrel Datwyler 		rc = 0;
568848c7085STyrel Datwyler 		break;
569848c7085STyrel Datwyler 	}
570848c7085STyrel Datwyler 
571848c7085STyrel Datwyler 	if (action >= IBMVFC_TGT_ACTION_LOGOUT_RPORT)
572848c7085STyrel Datwyler 		tgt->add_rport = 0;
573848c7085STyrel Datwyler 
574848c7085STyrel Datwyler 	return rc;
575848c7085STyrel Datwyler }
576848c7085STyrel Datwyler 
577848c7085STyrel Datwyler /**
578848c7085STyrel Datwyler  * ibmvfc_set_host_state - Set the state for the host
579848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
580848c7085STyrel Datwyler  * @state:		state to set host to
581848c7085STyrel Datwyler  *
582848c7085STyrel Datwyler  * Returns:
583848c7085STyrel Datwyler  *	0 if state changed / non-zero if not changed
584848c7085STyrel Datwyler  **/
ibmvfc_set_host_state(struct ibmvfc_host * vhost,enum ibmvfc_host_state state)585848c7085STyrel Datwyler static int ibmvfc_set_host_state(struct ibmvfc_host *vhost,
586848c7085STyrel Datwyler 				  enum ibmvfc_host_state state)
587848c7085STyrel Datwyler {
588848c7085STyrel Datwyler 	int rc = 0;
589848c7085STyrel Datwyler 
590848c7085STyrel Datwyler 	switch (vhost->state) {
591848c7085STyrel Datwyler 	case IBMVFC_HOST_OFFLINE:
592848c7085STyrel Datwyler 		rc = -EINVAL;
593848c7085STyrel Datwyler 		break;
594848c7085STyrel Datwyler 	default:
595848c7085STyrel Datwyler 		vhost->state = state;
596848c7085STyrel Datwyler 		break;
597848c7085STyrel Datwyler 	}
598848c7085STyrel Datwyler 
599848c7085STyrel Datwyler 	return rc;
600848c7085STyrel Datwyler }
601848c7085STyrel Datwyler 
602848c7085STyrel Datwyler /**
603848c7085STyrel Datwyler  * ibmvfc_set_host_action - Set the next init action for the host
604848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
605848c7085STyrel Datwyler  * @action:		action to perform
606848c7085STyrel Datwyler  *
607848c7085STyrel Datwyler  **/
ibmvfc_set_host_action(struct ibmvfc_host * vhost,enum ibmvfc_host_action action)608848c7085STyrel Datwyler static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
609848c7085STyrel Datwyler 				   enum ibmvfc_host_action action)
610848c7085STyrel Datwyler {
611848c7085STyrel Datwyler 	switch (action) {
612848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_ALLOC_TGTS:
613848c7085STyrel Datwyler 		if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT)
614848c7085STyrel Datwyler 			vhost->action = action;
615848c7085STyrel Datwyler 		break;
616848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_LOGO_WAIT:
617848c7085STyrel Datwyler 		if (vhost->action == IBMVFC_HOST_ACTION_LOGO)
618848c7085STyrel Datwyler 			vhost->action = action;
619848c7085STyrel Datwyler 		break;
620848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_INIT_WAIT:
621848c7085STyrel Datwyler 		if (vhost->action == IBMVFC_HOST_ACTION_INIT)
622848c7085STyrel Datwyler 			vhost->action = action;
623848c7085STyrel Datwyler 		break;
624848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_QUERY:
625848c7085STyrel Datwyler 		switch (vhost->action) {
626848c7085STyrel Datwyler 		case IBMVFC_HOST_ACTION_INIT_WAIT:
627848c7085STyrel Datwyler 		case IBMVFC_HOST_ACTION_NONE:
628848c7085STyrel Datwyler 		case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
629848c7085STyrel Datwyler 			vhost->action = action;
630848c7085STyrel Datwyler 			break;
631848c7085STyrel Datwyler 		default:
632848c7085STyrel Datwyler 			break;
633848c7085STyrel Datwyler 		}
634848c7085STyrel Datwyler 		break;
635848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_INIT:
636848c7085STyrel Datwyler 		if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
637848c7085STyrel Datwyler 			vhost->action = action;
638848c7085STyrel Datwyler 		break;
639848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_REENABLE:
640848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_RESET:
641848c7085STyrel Datwyler 		vhost->action = action;
642848c7085STyrel Datwyler 		break;
643848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_INIT:
644848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_DEL:
645848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_LOGO:
646848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_QUERY_TGTS:
647848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
648848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_NONE:
649848c7085STyrel Datwyler 	default:
650848c7085STyrel Datwyler 		switch (vhost->action) {
651848c7085STyrel Datwyler 		case IBMVFC_HOST_ACTION_RESET:
652848c7085STyrel Datwyler 		case IBMVFC_HOST_ACTION_REENABLE:
653848c7085STyrel Datwyler 			break;
654848c7085STyrel Datwyler 		default:
655848c7085STyrel Datwyler 			vhost->action = action;
656848c7085STyrel Datwyler 			break;
657848c7085STyrel Datwyler 		}
658848c7085STyrel Datwyler 		break;
659848c7085STyrel Datwyler 	}
660848c7085STyrel Datwyler }
661848c7085STyrel Datwyler 
662848c7085STyrel Datwyler /**
663848c7085STyrel Datwyler  * ibmvfc_reinit_host - Re-start host initialization (no NPIV Login)
664848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
665848c7085STyrel Datwyler  *
666848c7085STyrel Datwyler  * Return value:
667848c7085STyrel Datwyler  *	nothing
668848c7085STyrel Datwyler  **/
ibmvfc_reinit_host(struct ibmvfc_host * vhost)669848c7085STyrel Datwyler static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
670848c7085STyrel Datwyler {
671848c7085STyrel Datwyler 	if (vhost->action == IBMVFC_HOST_ACTION_NONE &&
672848c7085STyrel Datwyler 	    vhost->state == IBMVFC_ACTIVE) {
673848c7085STyrel Datwyler 		if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
674848c7085STyrel Datwyler 			scsi_block_requests(vhost->host);
675848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
676848c7085STyrel Datwyler 		}
677848c7085STyrel Datwyler 	} else
678848c7085STyrel Datwyler 		vhost->reinit = 1;
679848c7085STyrel Datwyler 
680848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
681848c7085STyrel Datwyler }
682848c7085STyrel Datwyler 
683848c7085STyrel Datwyler /**
684848c7085STyrel Datwyler  * ibmvfc_del_tgt - Schedule cleanup and removal of the target
685848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
686848c7085STyrel Datwyler  **/
ibmvfc_del_tgt(struct ibmvfc_target * tgt)687848c7085STyrel Datwyler static void ibmvfc_del_tgt(struct ibmvfc_target *tgt)
688848c7085STyrel Datwyler {
689848c7085STyrel Datwyler 	if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT)) {
690848c7085STyrel Datwyler 		tgt->job_step = ibmvfc_tgt_implicit_logout_and_del;
691848c7085STyrel Datwyler 		tgt->init_retries = 0;
692848c7085STyrel Datwyler 	}
693848c7085STyrel Datwyler 	wake_up(&tgt->vhost->work_wait_q);
694848c7085STyrel Datwyler }
695848c7085STyrel Datwyler 
696848c7085STyrel Datwyler /**
697848c7085STyrel Datwyler  * ibmvfc_link_down - Handle a link down event from the adapter
698848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
699848c7085STyrel Datwyler  * @state:	ibmvfc host state to enter
700848c7085STyrel Datwyler  *
701848c7085STyrel Datwyler  **/
ibmvfc_link_down(struct ibmvfc_host * vhost,enum ibmvfc_host_state state)702848c7085STyrel Datwyler static void ibmvfc_link_down(struct ibmvfc_host *vhost,
703848c7085STyrel Datwyler 			     enum ibmvfc_host_state state)
704848c7085STyrel Datwyler {
705848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
706848c7085STyrel Datwyler 
707848c7085STyrel Datwyler 	ENTER;
708848c7085STyrel Datwyler 	scsi_block_requests(vhost->host);
709848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
710848c7085STyrel Datwyler 		ibmvfc_del_tgt(tgt);
711e0fca728STyrel Datwyler 	list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
712e0fca728STyrel Datwyler 		ibmvfc_del_tgt(tgt);
713848c7085STyrel Datwyler 	ibmvfc_set_host_state(vhost, state);
714848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL);
715848c7085STyrel Datwyler 	vhost->events_to_log |= IBMVFC_AE_LINKDOWN;
716848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
717848c7085STyrel Datwyler 	LEAVE;
718848c7085STyrel Datwyler }
719848c7085STyrel Datwyler 
720848c7085STyrel Datwyler /**
721848c7085STyrel Datwyler  * ibmvfc_init_host - Start host initialization
722848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
723848c7085STyrel Datwyler  *
724848c7085STyrel Datwyler  * Return value:
725848c7085STyrel Datwyler  *	nothing
726848c7085STyrel Datwyler  **/
ibmvfc_init_host(struct ibmvfc_host * vhost)727848c7085STyrel Datwyler static void ibmvfc_init_host(struct ibmvfc_host *vhost)
728848c7085STyrel Datwyler {
729848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
730848c7085STyrel Datwyler 
731848c7085STyrel Datwyler 	if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {
732848c7085STyrel Datwyler 		if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) {
733848c7085STyrel Datwyler 			dev_err(vhost->dev,
734848c7085STyrel Datwyler 				"Host initialization retries exceeded. Taking adapter offline\n");
735848c7085STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
736848c7085STyrel Datwyler 			return;
737848c7085STyrel Datwyler 		}
738848c7085STyrel Datwyler 	}
739848c7085STyrel Datwyler 
740848c7085STyrel Datwyler 	if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
741848c7085STyrel Datwyler 		memset(vhost->async_crq.msgs.async, 0, PAGE_SIZE);
742848c7085STyrel Datwyler 		vhost->async_crq.cur = 0;
743848c7085STyrel Datwyler 
744848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
745848c7085STyrel Datwyler 			if (vhost->client_migrated)
746848c7085STyrel Datwyler 				tgt->need_login = 1;
747848c7085STyrel Datwyler 			else
748848c7085STyrel Datwyler 				ibmvfc_del_tgt(tgt);
749848c7085STyrel Datwyler 		}
750e0fca728STyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
751e0fca728STyrel Datwyler 			if (vhost->client_migrated)
752e0fca728STyrel Datwyler 				tgt->need_login = 1;
753e0fca728STyrel Datwyler 			else
754e0fca728STyrel Datwyler 				ibmvfc_del_tgt(tgt);
755e0fca728STyrel Datwyler 		}
756848c7085STyrel Datwyler 
757848c7085STyrel Datwyler 		scsi_block_requests(vhost->host);
758848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
759848c7085STyrel Datwyler 		vhost->job_step = ibmvfc_npiv_login;
760848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
761848c7085STyrel Datwyler 	}
762848c7085STyrel Datwyler }
763848c7085STyrel Datwyler 
764848c7085STyrel Datwyler /**
765848c7085STyrel Datwyler  * ibmvfc_send_crq - Send a CRQ
766848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
767848c7085STyrel Datwyler  * @word1:	the first 64 bits of the data
768848c7085STyrel Datwyler  * @word2:	the second 64 bits of the data
769848c7085STyrel Datwyler  *
770848c7085STyrel Datwyler  * Return value:
771848c7085STyrel Datwyler  *	0 on success / other on failure
772848c7085STyrel Datwyler  **/
ibmvfc_send_crq(struct ibmvfc_host * vhost,u64 word1,u64 word2)773848c7085STyrel Datwyler static int ibmvfc_send_crq(struct ibmvfc_host *vhost, u64 word1, u64 word2)
774848c7085STyrel Datwyler {
775848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
776848c7085STyrel Datwyler 	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
777848c7085STyrel Datwyler }
778848c7085STyrel Datwyler 
ibmvfc_send_sub_crq(struct ibmvfc_host * vhost,u64 cookie,u64 word1,u64 word2,u64 word3,u64 word4)779848c7085STyrel Datwyler static int ibmvfc_send_sub_crq(struct ibmvfc_host *vhost, u64 cookie, u64 word1,
780848c7085STyrel Datwyler 			       u64 word2, u64 word3, u64 word4)
781848c7085STyrel Datwyler {
782848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
783848c7085STyrel Datwyler 
784848c7085STyrel Datwyler 	return plpar_hcall_norets(H_SEND_SUB_CRQ, vdev->unit_address, cookie,
785848c7085STyrel Datwyler 				  word1, word2, word3, word4);
786848c7085STyrel Datwyler }
787848c7085STyrel Datwyler 
788848c7085STyrel Datwyler /**
789848c7085STyrel Datwyler  * ibmvfc_send_crq_init - Send a CRQ init message
790848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
791848c7085STyrel Datwyler  *
792848c7085STyrel Datwyler  * Return value:
793848c7085STyrel Datwyler  *	0 on success / other on failure
794848c7085STyrel Datwyler  **/
ibmvfc_send_crq_init(struct ibmvfc_host * vhost)795848c7085STyrel Datwyler static int ibmvfc_send_crq_init(struct ibmvfc_host *vhost)
796848c7085STyrel Datwyler {
797848c7085STyrel Datwyler 	ibmvfc_dbg(vhost, "Sending CRQ init\n");
798848c7085STyrel Datwyler 	return ibmvfc_send_crq(vhost, 0xC001000000000000LL, 0);
799848c7085STyrel Datwyler }
800848c7085STyrel Datwyler 
801848c7085STyrel Datwyler /**
802848c7085STyrel Datwyler  * ibmvfc_send_crq_init_complete - Send a CRQ init complete message
803848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
804848c7085STyrel Datwyler  *
805848c7085STyrel Datwyler  * Return value:
806848c7085STyrel Datwyler  *	0 on success / other on failure
807848c7085STyrel Datwyler  **/
ibmvfc_send_crq_init_complete(struct ibmvfc_host * vhost)808848c7085STyrel Datwyler static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost)
809848c7085STyrel Datwyler {
810848c7085STyrel Datwyler 	ibmvfc_dbg(vhost, "Sending CRQ init complete\n");
811848c7085STyrel Datwyler 	return ibmvfc_send_crq(vhost, 0xC002000000000000LL, 0);
812848c7085STyrel Datwyler }
813848c7085STyrel Datwyler 
814848c7085STyrel Datwyler /**
815848c7085STyrel Datwyler  * ibmvfc_init_event_pool - Allocates and initializes the event pool for a host
816848c7085STyrel Datwyler  * @vhost:	ibmvfc host who owns the event pool
817848c7085STyrel Datwyler  * @queue:      ibmvfc queue struct
818848c7085STyrel Datwyler  *
819848c7085STyrel Datwyler  * Returns zero on success.
820848c7085STyrel Datwyler  **/
ibmvfc_init_event_pool(struct ibmvfc_host * vhost,struct ibmvfc_queue * queue)821848c7085STyrel Datwyler static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost,
822848c7085STyrel Datwyler 				  struct ibmvfc_queue *queue)
823848c7085STyrel Datwyler {
824848c7085STyrel Datwyler 	int i;
825848c7085STyrel Datwyler 	struct ibmvfc_event_pool *pool = &queue->evt_pool;
826848c7085STyrel Datwyler 
827848c7085STyrel Datwyler 	ENTER;
828848c7085STyrel Datwyler 	if (!queue->total_depth)
829848c7085STyrel Datwyler 		return 0;
830848c7085STyrel Datwyler 
831848c7085STyrel Datwyler 	pool->size = queue->total_depth;
832848c7085STyrel Datwyler 	pool->events = kzalloc_objs(*pool->events, pool->size);
833848c7085STyrel Datwyler 	if (!pool->events)
834848c7085STyrel Datwyler 		return -ENOMEM;
835848c7085STyrel Datwyler 
836848c7085STyrel Datwyler 	pool->iu_storage = dma_alloc_coherent(vhost->dev,
837848c7085STyrel Datwyler 					      pool->size * sizeof(*pool->iu_storage),
838848c7085STyrel Datwyler 					      &pool->iu_token, 0);
839848c7085STyrel Datwyler 
840848c7085STyrel Datwyler 	if (!pool->iu_storage) {
841848c7085STyrel Datwyler 		kfree(pool->events);
842848c7085STyrel Datwyler 		return -ENOMEM;
843848c7085STyrel Datwyler 	}
844848c7085STyrel Datwyler 
845848c7085STyrel Datwyler 	INIT_LIST_HEAD(&queue->sent);
846848c7085STyrel Datwyler 	INIT_LIST_HEAD(&queue->free);
847848c7085STyrel Datwyler 	queue->evt_free = queue->evt_depth;
848848c7085STyrel Datwyler 	queue->reserved_free = queue->reserved_depth;
849848c7085STyrel Datwyler 	spin_lock_init(&queue->l_lock);
850848c7085STyrel Datwyler 
851848c7085STyrel Datwyler 	for (i = 0; i < pool->size; ++i) {
852848c7085STyrel Datwyler 		struct ibmvfc_event *evt = &pool->events[i];
853848c7085STyrel Datwyler 
854848c7085STyrel Datwyler 		/*
855848c7085STyrel Datwyler 		 * evt->active states
856848c7085STyrel Datwyler 		 *  1 = in flight
857848c7085STyrel Datwyler 		 *  0 = being completed
858848c7085STyrel Datwyler 		 * -1 = free/freed
859848c7085STyrel Datwyler 		 */
860848c7085STyrel Datwyler 		atomic_set(&evt->active, -1);
861848c7085STyrel Datwyler 		atomic_set(&evt->free, 1);
862848c7085STyrel Datwyler 		evt->crq.valid = 0x80;
863848c7085STyrel Datwyler 		evt->crq.ioba = cpu_to_be64(pool->iu_token + (sizeof(*evt->xfer_iu) * i));
864848c7085STyrel Datwyler 		evt->xfer_iu = pool->iu_storage + i;
865848c7085STyrel Datwyler 		evt->vhost = vhost;
866848c7085STyrel Datwyler 		evt->queue = queue;
867848c7085STyrel Datwyler 		evt->ext_list = NULL;
868848c7085STyrel Datwyler 		list_add_tail(&evt->queue_list, &queue->free);
869848c7085STyrel Datwyler 	}
870848c7085STyrel Datwyler 
871848c7085STyrel Datwyler 	LEAVE;
872848c7085STyrel Datwyler 	return 0;
873848c7085STyrel Datwyler }
874848c7085STyrel Datwyler 
875848c7085STyrel Datwyler /**
876848c7085STyrel Datwyler  * ibmvfc_free_event_pool - Frees memory of the event pool of a host
877848c7085STyrel Datwyler  * @vhost:	ibmvfc host who owns the event pool
878848c7085STyrel Datwyler  * @queue:      ibmvfc queue struct
879848c7085STyrel Datwyler  *
880848c7085STyrel Datwyler  **/
ibmvfc_free_event_pool(struct ibmvfc_host * vhost,struct ibmvfc_queue * queue)881848c7085STyrel Datwyler static void ibmvfc_free_event_pool(struct ibmvfc_host *vhost,
882848c7085STyrel Datwyler 				   struct ibmvfc_queue *queue)
883848c7085STyrel Datwyler {
884848c7085STyrel Datwyler 	int i;
885848c7085STyrel Datwyler 	struct ibmvfc_event_pool *pool = &queue->evt_pool;
886848c7085STyrel Datwyler 
887848c7085STyrel Datwyler 	ENTER;
888848c7085STyrel Datwyler 	for (i = 0; i < pool->size; ++i) {
889848c7085STyrel Datwyler 		list_del(&pool->events[i].queue_list);
890848c7085STyrel Datwyler 		BUG_ON(atomic_read(&pool->events[i].free) != 1);
891848c7085STyrel Datwyler 		if (pool->events[i].ext_list)
892848c7085STyrel Datwyler 			dma_pool_free(vhost->sg_pool,
893848c7085STyrel Datwyler 				      pool->events[i].ext_list,
894848c7085STyrel Datwyler 				      pool->events[i].ext_list_token);
895848c7085STyrel Datwyler 	}
896848c7085STyrel Datwyler 
897848c7085STyrel Datwyler 	kfree(pool->events);
898848c7085STyrel Datwyler 	dma_free_coherent(vhost->dev,
899848c7085STyrel Datwyler 			  pool->size * sizeof(*pool->iu_storage),
900848c7085STyrel Datwyler 			  pool->iu_storage, pool->iu_token);
901848c7085STyrel Datwyler 	LEAVE;
902848c7085STyrel Datwyler }
903848c7085STyrel Datwyler 
904848c7085STyrel Datwyler /**
905848c7085STyrel Datwyler  * ibmvfc_free_queue - Deallocate queue
906848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
907848c7085STyrel Datwyler  * @queue:	ibmvfc queue struct
908848c7085STyrel Datwyler  *
909848c7085STyrel Datwyler  * Unmaps dma and deallocates page for messages
910848c7085STyrel Datwyler  **/
ibmvfc_free_queue(struct ibmvfc_host * vhost,struct ibmvfc_queue * queue)911848c7085STyrel Datwyler static void ibmvfc_free_queue(struct ibmvfc_host *vhost,
912848c7085STyrel Datwyler 			      struct ibmvfc_queue *queue)
913848c7085STyrel Datwyler {
914848c7085STyrel Datwyler 	struct device *dev = vhost->dev;
915848c7085STyrel Datwyler 
916848c7085STyrel Datwyler 	dma_unmap_single(dev, queue->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
917848c7085STyrel Datwyler 	free_page((unsigned long)queue->msgs.handle);
918848c7085STyrel Datwyler 	queue->msgs.handle = NULL;
919848c7085STyrel Datwyler 
920848c7085STyrel Datwyler 	ibmvfc_free_event_pool(vhost, queue);
921848c7085STyrel Datwyler }
922848c7085STyrel Datwyler 
923848c7085STyrel Datwyler /**
924848c7085STyrel Datwyler  * ibmvfc_release_crq_queue - Deallocates data and unregisters CRQ
925848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
926848c7085STyrel Datwyler  *
927848c7085STyrel Datwyler  * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
928848c7085STyrel Datwyler  * the crq with the hypervisor.
929848c7085STyrel Datwyler  **/
ibmvfc_release_crq_queue(struct ibmvfc_host * vhost)930848c7085STyrel Datwyler static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
931848c7085STyrel Datwyler {
932848c7085STyrel Datwyler 	long rc = 0;
933848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
934848c7085STyrel Datwyler 	struct ibmvfc_queue *crq = &vhost->crq;
935848c7085STyrel Datwyler 
936848c7085STyrel Datwyler 	ibmvfc_dbg(vhost, "Releasing CRQ\n");
937848c7085STyrel Datwyler 	free_irq(vdev->irq, vhost);
938848c7085STyrel Datwyler 	tasklet_kill(&vhost->tasklet);
939848c7085STyrel Datwyler 	do {
940848c7085STyrel Datwyler 		if (rc)
941848c7085STyrel Datwyler 			msleep(100);
942848c7085STyrel Datwyler 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
943848c7085STyrel Datwyler 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
944848c7085STyrel Datwyler 
945848c7085STyrel Datwyler 	vhost->state = IBMVFC_NO_CRQ;
946848c7085STyrel Datwyler 	vhost->logged_in = 0;
947848c7085STyrel Datwyler 
948848c7085STyrel Datwyler 	ibmvfc_free_queue(vhost, crq);
949848c7085STyrel Datwyler }
950848c7085STyrel Datwyler 
951848c7085STyrel Datwyler /**
952848c7085STyrel Datwyler  * ibmvfc_reenable_crq_queue - reenables the CRQ
953848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
954848c7085STyrel Datwyler  *
955848c7085STyrel Datwyler  * Return value:
956848c7085STyrel Datwyler  *	0 on success / other on failure
957848c7085STyrel Datwyler  **/
ibmvfc_reenable_crq_queue(struct ibmvfc_host * vhost)958848c7085STyrel Datwyler static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
959848c7085STyrel Datwyler {
960848c7085STyrel Datwyler 	int rc = 0;
961848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
962848c7085STyrel Datwyler 	unsigned long flags;
963848c7085STyrel Datwyler 
964848c7085STyrel Datwyler 	ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs);
965319f6545STyrel Datwyler 	ibmvfc_dereg_sub_crqs(vhost, &vhost->nvme_scrqs);
966848c7085STyrel Datwyler 
967848c7085STyrel Datwyler 	/* Re-enable the CRQ */
968848c7085STyrel Datwyler 	do {
969848c7085STyrel Datwyler 		if (rc)
970848c7085STyrel Datwyler 			msleep(100);
971848c7085STyrel Datwyler 		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
972848c7085STyrel Datwyler 	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
973848c7085STyrel Datwyler 
974848c7085STyrel Datwyler 	if (rc)
975848c7085STyrel Datwyler 		dev_err(vhost->dev, "Error enabling adapter (rc=%d)\n", rc);
976848c7085STyrel Datwyler 
977848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
978848c7085STyrel Datwyler 	spin_lock(vhost->crq.q_lock);
979848c7085STyrel Datwyler 	vhost->do_enquiry = 1;
980848c7085STyrel Datwyler 	vhost->using_channels = 0;
981ecc03d95STyrel Datwyler 	vhost->do_scsi_login = 0;
982ecc03d95STyrel Datwyler 	vhost->do_nvme_login = 0;
983848c7085STyrel Datwyler 	spin_unlock(vhost->crq.q_lock);
984848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
985848c7085STyrel Datwyler 
986848c7085STyrel Datwyler 	ibmvfc_reg_sub_crqs(vhost, &vhost->scsi_scrqs);
987319f6545STyrel Datwyler 	ibmvfc_reg_sub_crqs(vhost, &vhost->nvme_scrqs);
988848c7085STyrel Datwyler 
989848c7085STyrel Datwyler 	return rc;
990848c7085STyrel Datwyler }
991848c7085STyrel Datwyler 
992848c7085STyrel Datwyler /**
993848c7085STyrel Datwyler  * ibmvfc_reset_crq - resets a crq after a failure
994848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
995848c7085STyrel Datwyler  *
996848c7085STyrel Datwyler  * Return value:
997848c7085STyrel Datwyler  *	0 on success / other on failure
998848c7085STyrel Datwyler  **/
ibmvfc_reset_crq(struct ibmvfc_host * vhost)999848c7085STyrel Datwyler static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
1000848c7085STyrel Datwyler {
1001848c7085STyrel Datwyler 	int rc = 0;
1002848c7085STyrel Datwyler 	unsigned long flags;
1003848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
1004848c7085STyrel Datwyler 	struct ibmvfc_queue *crq = &vhost->crq;
1005848c7085STyrel Datwyler 
1006848c7085STyrel Datwyler 	ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs);
1007319f6545STyrel Datwyler 	ibmvfc_dereg_sub_crqs(vhost, &vhost->nvme_scrqs);
1008848c7085STyrel Datwyler 
1009848c7085STyrel Datwyler 	/* Close the CRQ */
1010848c7085STyrel Datwyler 	do {
1011848c7085STyrel Datwyler 		if (rc)
1012848c7085STyrel Datwyler 			msleep(100);
1013848c7085STyrel Datwyler 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
1014848c7085STyrel Datwyler 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
1015848c7085STyrel Datwyler 
1016848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
1017848c7085STyrel Datwyler 	spin_lock(vhost->crq.q_lock);
1018848c7085STyrel Datwyler 	vhost->state = IBMVFC_NO_CRQ;
1019848c7085STyrel Datwyler 	vhost->logged_in = 0;
1020848c7085STyrel Datwyler 	vhost->do_enquiry = 1;
1021848c7085STyrel Datwyler 	vhost->using_channels = 0;
1022ecc03d95STyrel Datwyler 	vhost->do_scsi_login = 0;
1023ecc03d95STyrel Datwyler 	vhost->do_nvme_login = 0;
1024848c7085STyrel Datwyler 
1025848c7085STyrel Datwyler 	/* Clean out the queue */
1026848c7085STyrel Datwyler 	memset(crq->msgs.crq, 0, PAGE_SIZE);
1027848c7085STyrel Datwyler 	crq->cur = 0;
1028848c7085STyrel Datwyler 
1029848c7085STyrel Datwyler 	/* And re-open it again */
1030848c7085STyrel Datwyler 	rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
1031848c7085STyrel Datwyler 				crq->msg_token, PAGE_SIZE);
1032848c7085STyrel Datwyler 
1033848c7085STyrel Datwyler 	if (rc == H_CLOSED)
1034848c7085STyrel Datwyler 		/* Adapter is good, but other end is not ready */
1035848c7085STyrel Datwyler 		dev_warn(vhost->dev, "Partner adapter not ready\n");
1036848c7085STyrel Datwyler 	else if (rc != 0)
1037848c7085STyrel Datwyler 		dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc);
1038848c7085STyrel Datwyler 
1039848c7085STyrel Datwyler 	spin_unlock(vhost->crq.q_lock);
1040848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
1041848c7085STyrel Datwyler 
1042848c7085STyrel Datwyler 	ibmvfc_reg_sub_crqs(vhost, &vhost->scsi_scrqs);
1043319f6545STyrel Datwyler 	ibmvfc_reg_sub_crqs(vhost, &vhost->nvme_scrqs);
1044848c7085STyrel Datwyler 
1045848c7085STyrel Datwyler 	return rc;
1046848c7085STyrel Datwyler }
1047848c7085STyrel Datwyler 
1048848c7085STyrel Datwyler /**
1049848c7085STyrel Datwyler  * ibmvfc_valid_event - Determines if event is valid.
1050848c7085STyrel Datwyler  * @pool:	event_pool that contains the event
1051848c7085STyrel Datwyler  * @evt:	ibmvfc event to be checked for validity
1052848c7085STyrel Datwyler  *
1053848c7085STyrel Datwyler  * Return value:
1054848c7085STyrel Datwyler  *	1 if event is valid / 0 if event is not valid
1055848c7085STyrel Datwyler  **/
ibmvfc_valid_event(struct ibmvfc_event_pool * pool,struct ibmvfc_event * evt)1056848c7085STyrel Datwyler static int ibmvfc_valid_event(struct ibmvfc_event_pool *pool,
1057848c7085STyrel Datwyler 			      struct ibmvfc_event *evt)
1058848c7085STyrel Datwyler {
1059848c7085STyrel Datwyler 	int index = evt - pool->events;
1060848c7085STyrel Datwyler 	if (index < 0 || index >= pool->size)	/* outside of bounds */
1061848c7085STyrel Datwyler 		return 0;
1062848c7085STyrel Datwyler 	if (evt != pool->events + index)	/* unaligned */
1063848c7085STyrel Datwyler 		return 0;
1064848c7085STyrel Datwyler 	return 1;
1065848c7085STyrel Datwyler }
1066848c7085STyrel Datwyler 
1067848c7085STyrel Datwyler /**
1068848c7085STyrel Datwyler  * ibmvfc_free_event - Free the specified event
1069848c7085STyrel Datwyler  * @evt:	ibmvfc_event to be freed
1070848c7085STyrel Datwyler  *
1071848c7085STyrel Datwyler  **/
ibmvfc_free_event(struct ibmvfc_event * evt)10726fac8df9STyrel Datwyler void ibmvfc_free_event(struct ibmvfc_event *evt)
1073848c7085STyrel Datwyler {
1074848c7085STyrel Datwyler 	struct ibmvfc_event_pool *pool = &evt->queue->evt_pool;
1075848c7085STyrel Datwyler 	unsigned long flags;
1076848c7085STyrel Datwyler 
1077848c7085STyrel Datwyler 	BUG_ON(!ibmvfc_valid_event(pool, evt));
1078848c7085STyrel Datwyler 	BUG_ON(atomic_inc_return(&evt->free) != 1);
1079848c7085STyrel Datwyler 	BUG_ON(atomic_dec_and_test(&evt->active));
1080848c7085STyrel Datwyler 
1081848c7085STyrel Datwyler 	spin_lock_irqsave(&evt->queue->l_lock, flags);
1082848c7085STyrel Datwyler 	list_add_tail(&evt->queue_list, &evt->queue->free);
1083848c7085STyrel Datwyler 	if (evt->reserved) {
1084848c7085STyrel Datwyler 		evt->reserved = 0;
1085848c7085STyrel Datwyler 		evt->queue->reserved_free++;
1086848c7085STyrel Datwyler 	} else {
1087848c7085STyrel Datwyler 		evt->queue->evt_free++;
1088848c7085STyrel Datwyler 	}
1089848c7085STyrel Datwyler 	if (evt->eh_comp)
1090848c7085STyrel Datwyler 		complete(evt->eh_comp);
1091848c7085STyrel Datwyler 	spin_unlock_irqrestore(&evt->queue->l_lock, flags);
1092848c7085STyrel Datwyler }
1093848c7085STyrel Datwyler 
1094848c7085STyrel Datwyler /**
10954857949bSTyrel Datwyler  * ibmvfc_vfc_eh_done - EH done function for queued IO
1096848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
1097848c7085STyrel Datwyler  *
10984857949bSTyrel Datwyler  * This function does not setup any error status for scsi commands, that must be
10994857949bSTyrel Datwyler  * done before this function gets called.
1100848c7085STyrel Datwyler  **/
ibmvfc_vfc_eh_done(struct ibmvfc_event * evt)11014857949bSTyrel Datwyler static void ibmvfc_vfc_eh_done(struct ibmvfc_event *evt)
1102848c7085STyrel Datwyler {
1103848c7085STyrel Datwyler 	struct scsi_cmnd *cmnd = evt->cmnd;
11044857949bSTyrel Datwyler 	struct nvmefc_ls_req *ls_req = evt->ls_req;
11054857949bSTyrel Datwyler 	struct nvmefc_fcp_req *fcp_req = evt->fcp_req;
1106848c7085STyrel Datwyler 
1107848c7085STyrel Datwyler 	if (cmnd) {
1108848c7085STyrel Datwyler 		scsi_dma_unmap(cmnd);
1109848c7085STyrel Datwyler 		scsi_done(cmnd);
11104857949bSTyrel Datwyler 	} else if (fcp_req) {
11114857949bSTyrel Datwyler 		fcp_req->rcv_rsplen = 0;
11124857949bSTyrel Datwyler 		fcp_req->transferred_length = 0;
11134857949bSTyrel Datwyler 		fcp_req->status = NVME_SC_INTERNAL;
11144857949bSTyrel Datwyler 		fcp_req->done(fcp_req);
11154857949bSTyrel Datwyler 	} else if (ls_req) {
11164857949bSTyrel Datwyler 		ls_req->done(ls_req, -EIO);
11174857949bSTyrel Datwyler 		kref_put(&evt->tgt->kref, ibmvfc_release_tgt);
1118848c7085STyrel Datwyler 	}
1119848c7085STyrel Datwyler 
1120848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
1121848c7085STyrel Datwyler }
1122848c7085STyrel Datwyler 
1123848c7085STyrel Datwyler /**
1124848c7085STyrel Datwyler  * ibmvfc_complete_purge - Complete failed command list
1125848c7085STyrel Datwyler  * @purge_list:		list head of failed commands
1126848c7085STyrel Datwyler  *
1127848c7085STyrel Datwyler  * This function runs completions on commands to fail as a result of a
1128848c7085STyrel Datwyler  * host reset or platform migration.
1129848c7085STyrel Datwyler  **/
ibmvfc_complete_purge(struct list_head * purge_list)1130848c7085STyrel Datwyler static void ibmvfc_complete_purge(struct list_head *purge_list)
1131848c7085STyrel Datwyler {
1132848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *pos;
1133848c7085STyrel Datwyler 
1134848c7085STyrel Datwyler 	list_for_each_entry_safe(evt, pos, purge_list, queue_list) {
1135848c7085STyrel Datwyler 		list_del(&evt->queue_list);
1136848c7085STyrel Datwyler 		ibmvfc_trc_end(evt);
1137848c7085STyrel Datwyler 		evt->done(evt);
1138848c7085STyrel Datwyler 	}
1139848c7085STyrel Datwyler }
1140848c7085STyrel Datwyler 
1141848c7085STyrel Datwyler /**
1142848c7085STyrel Datwyler  * ibmvfc_fail_request - Fail request with specified error code
1143848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
1144848c7085STyrel Datwyler  * @error_code:	error code to fail request with
1145848c7085STyrel Datwyler  *
1146848c7085STyrel Datwyler  * Return value:
1147848c7085STyrel Datwyler  *	none
1148848c7085STyrel Datwyler  **/
ibmvfc_fail_request(struct ibmvfc_event * evt,int error_code)1149848c7085STyrel Datwyler static void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code)
1150848c7085STyrel Datwyler {
1151848c7085STyrel Datwyler 	/*
1152848c7085STyrel Datwyler 	 * Anything we are failing should still be active. Otherwise, it
1153848c7085STyrel Datwyler 	 * implies we already got a response for the command and are doing
1154848c7085STyrel Datwyler 	 * something bad like double completing it.
1155848c7085STyrel Datwyler 	 */
1156848c7085STyrel Datwyler 	BUG_ON(!atomic_dec_and_test(&evt->active));
1157848c7085STyrel Datwyler 	if (evt->cmnd) {
1158848c7085STyrel Datwyler 		evt->cmnd->result = (error_code << 16);
11594857949bSTyrel Datwyler 		evt->done = ibmvfc_vfc_eh_done;
11604857949bSTyrel Datwyler 	} else if (evt->fcp_req || evt->ls_req)
11614857949bSTyrel Datwyler 		evt->done = ibmvfc_vfc_eh_done;
11624857949bSTyrel Datwyler 	else
1163848c7085STyrel Datwyler 		evt->xfer_iu->mad_common.status = cpu_to_be16(IBMVFC_MAD_DRIVER_FAILED);
1164848c7085STyrel Datwyler 
1165848c7085STyrel Datwyler 	timer_delete(&evt->timer);
1166848c7085STyrel Datwyler }
1167848c7085STyrel Datwyler 
1168848c7085STyrel Datwyler /**
1169848c7085STyrel Datwyler  * ibmvfc_purge_requests - Our virtual adapter just shut down. Purge any sent requests
1170848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
1171848c7085STyrel Datwyler  * @error_code:	error code to fail requests with
1172848c7085STyrel Datwyler  *
1173848c7085STyrel Datwyler  * Return value:
1174848c7085STyrel Datwyler  *	none
1175848c7085STyrel Datwyler  **/
ibmvfc_purge_requests(struct ibmvfc_host * vhost,int error_code)1176848c7085STyrel Datwyler static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
1177848c7085STyrel Datwyler {
1178848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *pos;
11794857949bSTyrel Datwyler 	struct ibmvfc_queue *scsi_q = vhost->scsi_scrqs.scrqs;
11804857949bSTyrel Datwyler 	struct ibmvfc_queue *nvme_q = vhost->nvme_scrqs.scrqs;
1181848c7085STyrel Datwyler 	unsigned long flags;
11824857949bSTyrel Datwyler 	int shwqs, nhwqs = 0;
1183848c7085STyrel Datwyler 	int i;
1184848c7085STyrel Datwyler 
11854857949bSTyrel Datwyler 	if (vhost->using_channels) {
11864857949bSTyrel Datwyler 		shwqs = vhost->scsi_scrqs.active_queues;
11874857949bSTyrel Datwyler 		nhwqs = vhost->nvme_scrqs.active_queues;
11884857949bSTyrel Datwyler 	}
1189848c7085STyrel Datwyler 
1190848c7085STyrel Datwyler 	ibmvfc_dbg(vhost, "Purging all requests\n");
1191848c7085STyrel Datwyler 	spin_lock_irqsave(&vhost->crq.l_lock, flags);
1192848c7085STyrel Datwyler 	list_for_each_entry_safe(evt, pos, &vhost->crq.sent, queue_list)
1193848c7085STyrel Datwyler 		ibmvfc_fail_request(evt, error_code);
1194848c7085STyrel Datwyler 	list_splice_init(&vhost->crq.sent, &vhost->purge);
1195848c7085STyrel Datwyler 	spin_unlock_irqrestore(&vhost->crq.l_lock, flags);
1196848c7085STyrel Datwyler 
11974857949bSTyrel Datwyler 	for (i = 0; i < shwqs; i++) {
11984857949bSTyrel Datwyler 		spin_lock_irqsave(scsi_q[i].q_lock, flags);
11994857949bSTyrel Datwyler 		spin_lock(&scsi_q[i].l_lock);
12004857949bSTyrel Datwyler 		list_for_each_entry_safe(evt, pos, &scsi_q[i].sent, queue_list)
1201848c7085STyrel Datwyler 			ibmvfc_fail_request(evt, error_code);
12024857949bSTyrel Datwyler 		list_splice_init(&scsi_q[i].sent, &vhost->purge);
12034857949bSTyrel Datwyler 		spin_unlock(&scsi_q[i].l_lock);
12044857949bSTyrel Datwyler 		spin_unlock_irqrestore(scsi_q[i].q_lock, flags);
12054857949bSTyrel Datwyler 	}
12064857949bSTyrel Datwyler 
12074857949bSTyrel Datwyler 	for (i = 0; i < nhwqs; i++) {
12084857949bSTyrel Datwyler 		spin_lock_irqsave(nvme_q[i].q_lock, flags);
12094857949bSTyrel Datwyler 		spin_lock(&nvme_q[i].l_lock);
12104857949bSTyrel Datwyler 		list_for_each_entry_safe(evt, pos, &nvme_q[i].sent, queue_list)
12114857949bSTyrel Datwyler 			ibmvfc_fail_request(evt, error_code);
12124857949bSTyrel Datwyler 		list_splice_init(&nvme_q[i].sent, &vhost->purge);
12134857949bSTyrel Datwyler 		spin_unlock(&nvme_q[i].l_lock);
12144857949bSTyrel Datwyler 		spin_unlock_irqrestore(nvme_q[i].q_lock, flags);
1215848c7085STyrel Datwyler 	}
1216848c7085STyrel Datwyler }
1217848c7085STyrel Datwyler 
1218848c7085STyrel Datwyler /**
1219848c7085STyrel Datwyler  * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ
1220848c7085STyrel Datwyler  * @vhost:	struct ibmvfc host to reset
1221848c7085STyrel Datwyler  **/
ibmvfc_hard_reset_host(struct ibmvfc_host * vhost)1222848c7085STyrel Datwyler static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
1223848c7085STyrel Datwyler {
1224848c7085STyrel Datwyler 	ibmvfc_purge_requests(vhost, DID_ERROR);
1225848c7085STyrel Datwyler 	ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
1226848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
1227848c7085STyrel Datwyler }
1228848c7085STyrel Datwyler 
1229848c7085STyrel Datwyler /**
1230848c7085STyrel Datwyler  * __ibmvfc_reset_host - Reset the connection to the server (no locking)
1231848c7085STyrel Datwyler  * @vhost:	struct ibmvfc host to reset
1232848c7085STyrel Datwyler  **/
__ibmvfc_reset_host(struct ibmvfc_host * vhost)1233848c7085STyrel Datwyler static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
1234848c7085STyrel Datwyler {
1235848c7085STyrel Datwyler 	if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT &&
1236848c7085STyrel Datwyler 	    !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
1237848c7085STyrel Datwyler 		scsi_block_requests(vhost->host);
1238848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO);
1239848c7085STyrel Datwyler 		vhost->job_step = ibmvfc_npiv_logout;
1240848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
1241848c7085STyrel Datwyler 	} else
1242848c7085STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
1243848c7085STyrel Datwyler }
1244848c7085STyrel Datwyler 
1245848c7085STyrel Datwyler /**
1246848c7085STyrel Datwyler  * ibmvfc_reset_host - Reset the connection to the server
1247848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
1248848c7085STyrel Datwyler  **/
ibmvfc_reset_host(struct ibmvfc_host * vhost)1249848c7085STyrel Datwyler static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
1250848c7085STyrel Datwyler {
1251848c7085STyrel Datwyler 	unsigned long flags;
1252848c7085STyrel Datwyler 
1253848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
1254848c7085STyrel Datwyler 	__ibmvfc_reset_host(vhost);
1255848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
1256848c7085STyrel Datwyler }
1257848c7085STyrel Datwyler 
1258848c7085STyrel Datwyler /**
1259848c7085STyrel Datwyler  * ibmvfc_retry_host_init - Retry host initialization if allowed
1260848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
1261848c7085STyrel Datwyler  *
1262848c7085STyrel Datwyler  * Returns: 1 if init will be retried / 0 if not
1263848c7085STyrel Datwyler  *
1264848c7085STyrel Datwyler  **/
ibmvfc_retry_host_init(struct ibmvfc_host * vhost)1265848c7085STyrel Datwyler static int ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
1266848c7085STyrel Datwyler {
1267848c7085STyrel Datwyler 	int retry = 0;
1268848c7085STyrel Datwyler 
1269848c7085STyrel Datwyler 	if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {
1270848c7085STyrel Datwyler 		vhost->delay_init = 1;
1271848c7085STyrel Datwyler 		if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) {
1272848c7085STyrel Datwyler 			dev_err(vhost->dev,
1273848c7085STyrel Datwyler 				"Host initialization retries exceeded. Taking adapter offline\n");
1274848c7085STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
1275848c7085STyrel Datwyler 		} else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES)
1276848c7085STyrel Datwyler 			__ibmvfc_reset_host(vhost);
1277848c7085STyrel Datwyler 		else {
1278848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
1279848c7085STyrel Datwyler 			retry = 1;
1280848c7085STyrel Datwyler 		}
1281848c7085STyrel Datwyler 	}
1282848c7085STyrel Datwyler 
1283848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
1284848c7085STyrel Datwyler 	return retry;
1285848c7085STyrel Datwyler }
1286848c7085STyrel Datwyler 
1287848c7085STyrel Datwyler /**
1288848c7085STyrel Datwyler  * __ibmvfc_get_target - Find the specified scsi_target (no locking)
1289848c7085STyrel Datwyler  * @starget:	scsi target struct
1290848c7085STyrel Datwyler  *
1291848c7085STyrel Datwyler  * Return value:
1292848c7085STyrel Datwyler  *	ibmvfc_target struct / NULL if not found
1293848c7085STyrel Datwyler  **/
__ibmvfc_get_target(struct scsi_target * starget)1294848c7085STyrel Datwyler static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget)
1295848c7085STyrel Datwyler {
1296848c7085STyrel Datwyler 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
1297848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
1298848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
1299848c7085STyrel Datwyler 
1300848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
1301848c7085STyrel Datwyler 		if (tgt->target_id == starget->id) {
1302848c7085STyrel Datwyler 			kref_get(&tgt->kref);
1303848c7085STyrel Datwyler 			return tgt;
1304848c7085STyrel Datwyler 		}
1305848c7085STyrel Datwyler 	return NULL;
1306848c7085STyrel Datwyler }
1307848c7085STyrel Datwyler 
1308848c7085STyrel Datwyler /**
1309848c7085STyrel Datwyler  * ibmvfc_get_target - Find the specified scsi_target
1310848c7085STyrel Datwyler  * @starget:	scsi target struct
1311848c7085STyrel Datwyler  *
1312848c7085STyrel Datwyler  * Return value:
1313848c7085STyrel Datwyler  *	ibmvfc_target struct / NULL if not found
1314848c7085STyrel Datwyler  **/
ibmvfc_get_target(struct scsi_target * starget)1315848c7085STyrel Datwyler static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget)
1316848c7085STyrel Datwyler {
1317848c7085STyrel Datwyler 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
1318848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
1319848c7085STyrel Datwyler 	unsigned long flags;
1320848c7085STyrel Datwyler 
1321848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
1322848c7085STyrel Datwyler 	tgt = __ibmvfc_get_target(starget);
1323848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
1324848c7085STyrel Datwyler 	return tgt;
1325848c7085STyrel Datwyler }
1326848c7085STyrel Datwyler 
1327848c7085STyrel Datwyler /**
1328848c7085STyrel Datwyler  * ibmvfc_get_host_speed - Get host port speed
1329848c7085STyrel Datwyler  * @shost:		scsi host struct
1330848c7085STyrel Datwyler  *
1331848c7085STyrel Datwyler  * Return value:
1332848c7085STyrel Datwyler  * 	none
1333848c7085STyrel Datwyler  **/
ibmvfc_get_host_speed(struct Scsi_Host * shost)1334848c7085STyrel Datwyler static void ibmvfc_get_host_speed(struct Scsi_Host *shost)
1335848c7085STyrel Datwyler {
1336848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
1337848c7085STyrel Datwyler 	unsigned long flags;
1338848c7085STyrel Datwyler 
1339848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
1340848c7085STyrel Datwyler 	if (vhost->state == IBMVFC_ACTIVE) {
1341848c7085STyrel Datwyler 		switch (be64_to_cpu(vhost->login_buf->resp.link_speed) / 100) {
1342848c7085STyrel Datwyler 		case 1:
1343848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
1344848c7085STyrel Datwyler 			break;
1345848c7085STyrel Datwyler 		case 2:
1346848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
1347848c7085STyrel Datwyler 			break;
1348848c7085STyrel Datwyler 		case 4:
1349848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
1350848c7085STyrel Datwyler 			break;
1351848c7085STyrel Datwyler 		case 8:
1352848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
1353848c7085STyrel Datwyler 			break;
1354848c7085STyrel Datwyler 		case 10:
1355848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
1356848c7085STyrel Datwyler 			break;
1357848c7085STyrel Datwyler 		case 16:
1358848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_16GBIT;
1359848c7085STyrel Datwyler 			break;
1360848c7085STyrel Datwyler 		default:
1361848c7085STyrel Datwyler 			ibmvfc_log(vhost, 3, "Unknown port speed: %lld Gbit\n",
1362848c7085STyrel Datwyler 				   be64_to_cpu(vhost->login_buf->resp.link_speed) / 100);
1363848c7085STyrel Datwyler 			fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
1364848c7085STyrel Datwyler 			break;
1365848c7085STyrel Datwyler 		}
1366848c7085STyrel Datwyler 	} else
1367848c7085STyrel Datwyler 		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
1368848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
1369848c7085STyrel Datwyler }
1370848c7085STyrel Datwyler 
1371848c7085STyrel Datwyler /**
1372848c7085STyrel Datwyler  * ibmvfc_get_host_port_state - Get host port state
1373848c7085STyrel Datwyler  * @shost:		scsi host struct
1374848c7085STyrel Datwyler  *
1375848c7085STyrel Datwyler  * Return value:
1376848c7085STyrel Datwyler  * 	none
1377848c7085STyrel Datwyler  **/
ibmvfc_get_host_port_state(struct Scsi_Host * shost)1378848c7085STyrel Datwyler static void ibmvfc_get_host_port_state(struct Scsi_Host *shost)
1379848c7085STyrel Datwyler {
1380848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
1381848c7085STyrel Datwyler 	unsigned long flags;
1382848c7085STyrel Datwyler 
1383848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
1384848c7085STyrel Datwyler 	switch (vhost->state) {
1385848c7085STyrel Datwyler 	case IBMVFC_INITIALIZING:
1386848c7085STyrel Datwyler 	case IBMVFC_ACTIVE:
1387848c7085STyrel Datwyler 		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
1388848c7085STyrel Datwyler 		break;
1389848c7085STyrel Datwyler 	case IBMVFC_LINK_DOWN:
1390848c7085STyrel Datwyler 		fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
1391848c7085STyrel Datwyler 		break;
1392848c7085STyrel Datwyler 	case IBMVFC_LINK_DEAD:
1393848c7085STyrel Datwyler 	case IBMVFC_HOST_OFFLINE:
1394848c7085STyrel Datwyler 		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
1395848c7085STyrel Datwyler 		break;
1396848c7085STyrel Datwyler 	case IBMVFC_HALTED:
1397848c7085STyrel Datwyler 		fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
1398848c7085STyrel Datwyler 		break;
1399848c7085STyrel Datwyler 	case IBMVFC_NO_CRQ:
1400848c7085STyrel Datwyler 		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
1401848c7085STyrel Datwyler 		break;
1402848c7085STyrel Datwyler 	default:
1403848c7085STyrel Datwyler 		ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
1404848c7085STyrel Datwyler 		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
1405848c7085STyrel Datwyler 		break;
1406848c7085STyrel Datwyler 	}
1407848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
1408848c7085STyrel Datwyler }
1409848c7085STyrel Datwyler 
1410848c7085STyrel Datwyler /**
1411848c7085STyrel Datwyler  * ibmvfc_set_rport_dev_loss_tmo - Set rport's device loss timeout
1412848c7085STyrel Datwyler  * @rport:		rport struct
1413848c7085STyrel Datwyler  * @timeout:	timeout value
1414848c7085STyrel Datwyler  *
1415848c7085STyrel Datwyler  * Return value:
1416848c7085STyrel Datwyler  * 	none
1417848c7085STyrel Datwyler  **/
ibmvfc_set_rport_dev_loss_tmo(struct fc_rport * rport,u32 timeout)1418848c7085STyrel Datwyler static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
1419848c7085STyrel Datwyler {
1420848c7085STyrel Datwyler 	if (timeout)
1421848c7085STyrel Datwyler 		rport->dev_loss_tmo = timeout;
1422848c7085STyrel Datwyler 	else
1423848c7085STyrel Datwyler 		rport->dev_loss_tmo = 1;
1424848c7085STyrel Datwyler }
1425848c7085STyrel Datwyler 
1426848c7085STyrel Datwyler /**
1427848c7085STyrel Datwyler  * ibmvfc_release_tgt - Free memory allocated for a target
1428848c7085STyrel Datwyler  * @kref:		kref struct
1429848c7085STyrel Datwyler  *
1430848c7085STyrel Datwyler  **/
ibmvfc_release_tgt(struct kref * kref)14316fac8df9STyrel Datwyler void ibmvfc_release_tgt(struct kref *kref)
1432848c7085STyrel Datwyler {
1433848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
1434848c7085STyrel Datwyler 	mempool_free(tgt, tgt->vhost->tgt_pool);
1435848c7085STyrel Datwyler }
1436848c7085STyrel Datwyler 
1437848c7085STyrel Datwyler /**
1438848c7085STyrel Datwyler  * ibmvfc_get_starget_node_name - Get SCSI target's node name
1439848c7085STyrel Datwyler  * @starget:	scsi target struct
1440848c7085STyrel Datwyler  *
1441848c7085STyrel Datwyler  * Return value:
1442848c7085STyrel Datwyler  * 	none
1443848c7085STyrel Datwyler  **/
ibmvfc_get_starget_node_name(struct scsi_target * starget)1444848c7085STyrel Datwyler static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
1445848c7085STyrel Datwyler {
1446848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
1447848c7085STyrel Datwyler 	fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
1448848c7085STyrel Datwyler 	if (tgt)
1449848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
1450848c7085STyrel Datwyler }
1451848c7085STyrel Datwyler 
1452848c7085STyrel Datwyler /**
1453848c7085STyrel Datwyler  * ibmvfc_get_starget_port_name - Get SCSI target's port name
1454848c7085STyrel Datwyler  * @starget:	scsi target struct
1455848c7085STyrel Datwyler  *
1456848c7085STyrel Datwyler  * Return value:
1457848c7085STyrel Datwyler  * 	none
1458848c7085STyrel Datwyler  **/
ibmvfc_get_starget_port_name(struct scsi_target * starget)1459848c7085STyrel Datwyler static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
1460848c7085STyrel Datwyler {
1461848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
1462848c7085STyrel Datwyler 	fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
1463848c7085STyrel Datwyler 	if (tgt)
1464848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
1465848c7085STyrel Datwyler }
1466848c7085STyrel Datwyler 
1467848c7085STyrel Datwyler /**
1468848c7085STyrel Datwyler  * ibmvfc_get_starget_port_id - Get SCSI target's port ID
1469848c7085STyrel Datwyler  * @starget:	scsi target struct
1470848c7085STyrel Datwyler  *
1471848c7085STyrel Datwyler  * Return value:
1472848c7085STyrel Datwyler  * 	none
1473848c7085STyrel Datwyler  **/
ibmvfc_get_starget_port_id(struct scsi_target * starget)1474848c7085STyrel Datwyler static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
1475848c7085STyrel Datwyler {
1476848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
1477848c7085STyrel Datwyler 	fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
1478848c7085STyrel Datwyler 	if (tgt)
1479848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
1480848c7085STyrel Datwyler }
1481848c7085STyrel Datwyler 
1482848c7085STyrel Datwyler /**
1483848c7085STyrel Datwyler  * ibmvfc_wait_while_resetting - Wait while the host resets
1484848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
1485848c7085STyrel Datwyler  *
1486848c7085STyrel Datwyler  * Return value:
1487848c7085STyrel Datwyler  * 	0 on success / other on failure
1488848c7085STyrel Datwyler  **/
ibmvfc_wait_while_resetting(struct ibmvfc_host * vhost)1489848c7085STyrel Datwyler static int ibmvfc_wait_while_resetting(struct ibmvfc_host *vhost)
1490848c7085STyrel Datwyler {
1491848c7085STyrel Datwyler 	long timeout = wait_event_timeout(vhost->init_wait_q,
1492848c7085STyrel Datwyler 					  ((vhost->state == IBMVFC_ACTIVE ||
1493848c7085STyrel Datwyler 					    vhost->state == IBMVFC_HOST_OFFLINE ||
1494848c7085STyrel Datwyler 					    vhost->state == IBMVFC_LINK_DEAD) &&
1495848c7085STyrel Datwyler 					   vhost->action == IBMVFC_HOST_ACTION_NONE),
1496848c7085STyrel Datwyler 					  (init_timeout * HZ));
1497848c7085STyrel Datwyler 
1498848c7085STyrel Datwyler 	return timeout ? 0 : -EIO;
1499848c7085STyrel Datwyler }
1500848c7085STyrel Datwyler 
1501848c7085STyrel Datwyler /**
1502848c7085STyrel Datwyler  * ibmvfc_issue_fc_host_lip - Re-initiate link initialization
1503848c7085STyrel Datwyler  * @shost:		scsi host struct
1504848c7085STyrel Datwyler  *
1505848c7085STyrel Datwyler  * Return value:
1506848c7085STyrel Datwyler  * 	0 on success / other on failure
1507848c7085STyrel Datwyler  **/
ibmvfc_issue_fc_host_lip(struct Scsi_Host * shost)1508848c7085STyrel Datwyler static int ibmvfc_issue_fc_host_lip(struct Scsi_Host *shost)
1509848c7085STyrel Datwyler {
1510848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
1511848c7085STyrel Datwyler 
1512848c7085STyrel Datwyler 	dev_err(vhost->dev, "Initiating host LIP. Resetting connection\n");
1513848c7085STyrel Datwyler 	ibmvfc_reset_host(vhost);
1514848c7085STyrel Datwyler 	return ibmvfc_wait_while_resetting(vhost);
1515848c7085STyrel Datwyler }
1516848c7085STyrel Datwyler 
1517848c7085STyrel Datwyler /**
1518848c7085STyrel Datwyler  * ibmvfc_gather_partition_info - Gather info about the LPAR
1519848c7085STyrel Datwyler  * @vhost:      ibmvfc host struct
1520848c7085STyrel Datwyler  *
1521848c7085STyrel Datwyler  * Return value:
1522848c7085STyrel Datwyler  *	none
1523848c7085STyrel Datwyler  **/
ibmvfc_gather_partition_info(struct ibmvfc_host * vhost)1524848c7085STyrel Datwyler static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost)
1525848c7085STyrel Datwyler {
1526848c7085STyrel Datwyler 	struct device_node *rootdn;
1527848c7085STyrel Datwyler 	const char *name;
1528848c7085STyrel Datwyler 	const unsigned int *num;
1529848c7085STyrel Datwyler 
1530848c7085STyrel Datwyler 	rootdn = of_find_node_by_path("/");
1531848c7085STyrel Datwyler 	if (!rootdn)
1532848c7085STyrel Datwyler 		return;
1533848c7085STyrel Datwyler 
1534848c7085STyrel Datwyler 	name = of_get_property(rootdn, "ibm,partition-name", NULL);
1535848c7085STyrel Datwyler 	if (name)
1536848c7085STyrel Datwyler 		strscpy(vhost->partition_name, name, sizeof(vhost->partition_name));
1537848c7085STyrel Datwyler 	num = of_get_property(rootdn, "ibm,partition-no", NULL);
1538848c7085STyrel Datwyler 	if (num)
1539848c7085STyrel Datwyler 		vhost->partition_number = *num;
1540848c7085STyrel Datwyler 	of_node_put(rootdn);
1541848c7085STyrel Datwyler }
1542848c7085STyrel Datwyler 
1543848c7085STyrel Datwyler /**
1544848c7085STyrel Datwyler  * ibmvfc_set_login_info - Setup info for NPIV login
1545848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
1546848c7085STyrel Datwyler  *
1547848c7085STyrel Datwyler  * Return value:
1548848c7085STyrel Datwyler  *	none
1549848c7085STyrel Datwyler  **/
ibmvfc_set_login_info(struct ibmvfc_host * vhost)1550848c7085STyrel Datwyler static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
1551848c7085STyrel Datwyler {
1552848c7085STyrel Datwyler 	struct ibmvfc_npiv_login *login_info = &vhost->login_info;
1553848c7085STyrel Datwyler 	struct ibmvfc_queue *async_crq = &vhost->async_crq;
1554848c7085STyrel Datwyler 	struct device_node *of_node = vhost->dev->of_node;
1555848c7085STyrel Datwyler 	const char *location;
1556848c7085STyrel Datwyler 	u16 max_cmds;
1557848c7085STyrel Datwyler 
1558848c7085STyrel Datwyler 	max_cmds = scsi_qdepth + IBMVFC_NUM_INTERNAL_REQ;
1559848c7085STyrel Datwyler 	if (mq_enabled)
1560848c7085STyrel Datwyler 		max_cmds += (scsi_qdepth + IBMVFC_NUM_INTERNAL_SUBQ_REQ) *
1561ecc03d95STyrel Datwyler 			(vhost->scsi_scrqs.desired_queues + vhost->nvme_scrqs.desired_queues);
1562848c7085STyrel Datwyler 
1563848c7085STyrel Datwyler 	memset(login_info, 0, sizeof(*login_info));
1564848c7085STyrel Datwyler 
1565848c7085STyrel Datwyler 	login_info->ostype = cpu_to_be32(IBMVFC_OS_LINUX);
1566848c7085STyrel Datwyler 	login_info->max_dma_len = cpu_to_be64(max_sectors << 9);
156773c13e30STyrel Datwyler 	login_info->max_payload = cpu_to_be32(sizeof(struct nvme_fc_cmd_iu));
1568848c7085STyrel Datwyler 	login_info->max_response = cpu_to_be32(sizeof(struct ibmvfc_fcp_rsp));
1569848c7085STyrel Datwyler 	login_info->partition_num = cpu_to_be32(vhost->partition_number);
1570848c7085STyrel Datwyler 	login_info->vfc_frame_version = cpu_to_be32(1);
1571848c7085STyrel Datwyler 	login_info->fcp_version = cpu_to_be16(3);
1572848c7085STyrel Datwyler 	login_info->flags = cpu_to_be16(IBMVFC_FLUSH_ON_HALT);
1573848c7085STyrel Datwyler 	if (vhost->client_migrated)
1574848c7085STyrel Datwyler 		login_info->flags |= cpu_to_be16(IBMVFC_CLIENT_MIGRATED);
1575848c7085STyrel Datwyler 
1576848c7085STyrel Datwyler 	login_info->max_cmds = cpu_to_be32(max_cmds);
1577848c7085STyrel Datwyler 	login_info->capabilities = cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN);
1578848c7085STyrel Datwyler 
1579ecc03d95STyrel Datwyler 	if (vhost->mq_enabled || vhost->using_channels) {
1580848c7085STyrel Datwyler 		login_info->capabilities |= cpu_to_be64(IBMVFC_CAN_USE_CHANNELS);
1581ecc03d95STyrel Datwyler 		if (vhost->nvme_enabled) {
1582ecc03d95STyrel Datwyler 			login_info->capabilities |= cpu_to_be64(IBMVFC_YES_NVMEOF);
1583ecc03d95STyrel Datwyler 			login_info->capabilities |= cpu_to_be64(IBMVFC_YES_SCSI);
1584ecc03d95STyrel Datwyler 			login_info->capabilities |= cpu_to_be64(IBMVFC_CAN_USE_WWPN_ALL);
1585ecc03d95STyrel Datwyler 		}
1586ecc03d95STyrel Datwyler 	}
1587848c7085STyrel Datwyler 
1588848c7085STyrel Datwyler 	login_info->async.va = cpu_to_be64(vhost->async_crq.msg_token);
1589848c7085STyrel Datwyler 	login_info->async.len = cpu_to_be32(async_crq->size *
1590848c7085STyrel Datwyler 					    sizeof(*async_crq->msgs.async));
1591848c7085STyrel Datwyler 	strscpy(login_info->partition_name, vhost->partition_name,
1592848c7085STyrel Datwyler 		sizeof(login_info->partition_name));
1593848c7085STyrel Datwyler 
1594848c7085STyrel Datwyler 	strscpy(login_info->device_name,
1595848c7085STyrel Datwyler 		dev_name(&vhost->host->shost_gendev), sizeof(login_info->device_name));
1596848c7085STyrel Datwyler 
1597848c7085STyrel Datwyler 	location = of_get_property(of_node, "ibm,loc-code", NULL);
1598848c7085STyrel Datwyler 	location = location ? location : dev_name(vhost->dev);
1599848c7085STyrel Datwyler 	strscpy(login_info->drc_name, location, sizeof(login_info->drc_name));
1600848c7085STyrel Datwyler }
1601848c7085STyrel Datwyler 
1602848c7085STyrel Datwyler /**
1603848c7085STyrel Datwyler  * __ibmvfc_get_event - Gets the next free event in pool
1604848c7085STyrel Datwyler  * @queue:      ibmvfc queue struct
1605848c7085STyrel Datwyler  * @reserved:	event is for a reserved management command
1606848c7085STyrel Datwyler  *
1607848c7085STyrel Datwyler  * Returns a free event from the pool.
1608848c7085STyrel Datwyler  **/
__ibmvfc_get_event(struct ibmvfc_queue * queue,int reserved)16096fac8df9STyrel Datwyler struct ibmvfc_event *__ibmvfc_get_event(struct ibmvfc_queue *queue, int reserved)
1610848c7085STyrel Datwyler {
1611848c7085STyrel Datwyler 	struct ibmvfc_event *evt = NULL;
1612848c7085STyrel Datwyler 	unsigned long flags;
1613848c7085STyrel Datwyler 
1614848c7085STyrel Datwyler 	spin_lock_irqsave(&queue->l_lock, flags);
1615848c7085STyrel Datwyler 	if (reserved && queue->reserved_free) {
1616848c7085STyrel Datwyler 		evt = list_entry(queue->free.next, struct ibmvfc_event, queue_list);
1617848c7085STyrel Datwyler 		evt->reserved = 1;
1618848c7085STyrel Datwyler 		queue->reserved_free--;
1619848c7085STyrel Datwyler 	} else if (queue->evt_free) {
1620848c7085STyrel Datwyler 		evt = list_entry(queue->free.next, struct ibmvfc_event, queue_list);
1621848c7085STyrel Datwyler 		queue->evt_free--;
1622848c7085STyrel Datwyler 	} else {
1623848c7085STyrel Datwyler 		goto out;
1624848c7085STyrel Datwyler 	}
1625848c7085STyrel Datwyler 
1626848c7085STyrel Datwyler 	atomic_set(&evt->free, 0);
1627848c7085STyrel Datwyler 	list_del(&evt->queue_list);
1628848c7085STyrel Datwyler out:
1629848c7085STyrel Datwyler 	spin_unlock_irqrestore(&queue->l_lock, flags);
1630848c7085STyrel Datwyler 	return evt;
1631848c7085STyrel Datwyler }
1632848c7085STyrel Datwyler 
1633848c7085STyrel Datwyler /**
1634848c7085STyrel Datwyler  * ibmvfc_locked_done - Calls evt completion with host_lock held
1635848c7085STyrel Datwyler  * @evt:	ibmvfc evt to complete
1636848c7085STyrel Datwyler  *
1637848c7085STyrel Datwyler  * All non-scsi command completion callbacks have the expectation that the
1638848c7085STyrel Datwyler  * host_lock is held. This callback is used by ibmvfc_init_event to wrap a
1639848c7085STyrel Datwyler  * MAD evt with the host_lock.
1640848c7085STyrel Datwyler  **/
ibmvfc_locked_done(struct ibmvfc_event * evt)1641848c7085STyrel Datwyler static void ibmvfc_locked_done(struct ibmvfc_event *evt)
1642848c7085STyrel Datwyler {
1643848c7085STyrel Datwyler 	unsigned long flags;
1644848c7085STyrel Datwyler 
1645848c7085STyrel Datwyler 	spin_lock_irqsave(evt->vhost->host->host_lock, flags);
1646848c7085STyrel Datwyler 	evt->_done(evt);
1647848c7085STyrel Datwyler 	spin_unlock_irqrestore(evt->vhost->host->host_lock, flags);
1648848c7085STyrel Datwyler }
1649848c7085STyrel Datwyler 
1650848c7085STyrel Datwyler /**
1651848c7085STyrel Datwyler  * ibmvfc_init_event - Initialize fields in an event struct that are always
1652848c7085STyrel Datwyler  *				required.
1653848c7085STyrel Datwyler  * @evt:	The event
1654848c7085STyrel Datwyler  * @done:	Routine to call when the event is responded to
1655848c7085STyrel Datwyler  * @format:	SRP or MAD format
1656848c7085STyrel Datwyler  **/
ibmvfc_init_event(struct ibmvfc_event * evt,void (* done)(struct ibmvfc_event *),u8 format)16576fac8df9STyrel Datwyler void ibmvfc_init_event(struct ibmvfc_event *evt,
1658848c7085STyrel Datwyler 			      void (*done) (struct ibmvfc_event *), u8 format)
1659848c7085STyrel Datwyler {
1660848c7085STyrel Datwyler 	evt->cmnd = NULL;
166173c13e30STyrel Datwyler 	evt->fcp_req = NULL;
16627088e1c8STyrel Datwyler 	evt->ls_req = NULL;
1663848c7085STyrel Datwyler 	evt->sync_iu = NULL;
1664848c7085STyrel Datwyler 	evt->eh_comp = NULL;
1665848c7085STyrel Datwyler 	evt->crq.format = format;
1666848c7085STyrel Datwyler 	if (format == IBMVFC_CMD_FORMAT)
1667848c7085STyrel Datwyler 		evt->done = done;
1668848c7085STyrel Datwyler 	else {
1669848c7085STyrel Datwyler 		evt->_done = done;
1670848c7085STyrel Datwyler 		evt->done = ibmvfc_locked_done;
1671848c7085STyrel Datwyler 	}
1672848c7085STyrel Datwyler 	evt->hwq = 0;
1673848c7085STyrel Datwyler }
1674848c7085STyrel Datwyler 
1675848c7085STyrel Datwyler /**
1676848c7085STyrel Datwyler  * ibmvfc_map_sg_list - Initialize scatterlist
1677848c7085STyrel Datwyler  * @scmd:	scsi command struct
1678848c7085STyrel Datwyler  * @nseg:	number of scatterlist segments
1679848c7085STyrel Datwyler  * @md:	memory descriptor list to initialize
1680848c7085STyrel Datwyler  **/
ibmvfc_map_sg_list(struct scsi_cmnd * scmd,int nseg,struct srp_direct_buf * md)1681848c7085STyrel Datwyler static void ibmvfc_map_sg_list(struct scsi_cmnd *scmd, int nseg,
1682848c7085STyrel Datwyler 			       struct srp_direct_buf *md)
1683848c7085STyrel Datwyler {
1684848c7085STyrel Datwyler 	int i;
1685848c7085STyrel Datwyler 	struct scatterlist *sg;
1686848c7085STyrel Datwyler 
1687848c7085STyrel Datwyler 	scsi_for_each_sg(scmd, sg, nseg, i) {
1688848c7085STyrel Datwyler 		md[i].va = cpu_to_be64(sg_dma_address(sg));
1689848c7085STyrel Datwyler 		md[i].len = cpu_to_be32(sg_dma_len(sg));
1690848c7085STyrel Datwyler 		md[i].key = 0;
1691848c7085STyrel Datwyler 	}
1692848c7085STyrel Datwyler }
1693848c7085STyrel Datwyler 
1694848c7085STyrel Datwyler /**
1695848c7085STyrel Datwyler  * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes descriptor fields
1696848c7085STyrel Datwyler  * @scmd:		struct scsi_cmnd with the scatterlist
1697848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
1698848c7085STyrel Datwyler  * @vfc_cmd:	vfc_cmd that contains the memory descriptor
1699848c7085STyrel Datwyler  * @dev:		device for which to map dma memory
1700848c7085STyrel Datwyler  *
1701848c7085STyrel Datwyler  * Returns:
1702848c7085STyrel Datwyler  *	0 on success / non-zero on failure
1703848c7085STyrel Datwyler  **/
ibmvfc_map_sg_data(struct scsi_cmnd * scmd,struct ibmvfc_event * evt,struct ibmvfc_cmd * vfc_cmd,struct device * dev)1704848c7085STyrel Datwyler static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd,
1705848c7085STyrel Datwyler 			      struct ibmvfc_event *evt,
1706848c7085STyrel Datwyler 			      struct ibmvfc_cmd *vfc_cmd, struct device *dev)
1707848c7085STyrel Datwyler {
1708848c7085STyrel Datwyler 
1709848c7085STyrel Datwyler 	int sg_mapped;
1710848c7085STyrel Datwyler 	struct srp_direct_buf *data = &vfc_cmd->ioba;
1711848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = dev_get_drvdata(dev);
1712848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(evt->vhost, vfc_cmd);
1713848c7085STyrel Datwyler 
1714848c7085STyrel Datwyler 	if (cls3_error)
1715848c7085STyrel Datwyler 		vfc_cmd->flags |= cpu_to_be16(IBMVFC_CLASS_3_ERR);
1716848c7085STyrel Datwyler 
1717848c7085STyrel Datwyler 	sg_mapped = scsi_dma_map(scmd);
1718848c7085STyrel Datwyler 	if (!sg_mapped) {
1719848c7085STyrel Datwyler 		vfc_cmd->flags |= cpu_to_be16(IBMVFC_NO_MEM_DESC);
1720848c7085STyrel Datwyler 		return 0;
1721848c7085STyrel Datwyler 	} else if (unlikely(sg_mapped < 0)) {
1722848c7085STyrel Datwyler 		if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL)
1723848c7085STyrel Datwyler 			scmd_printk(KERN_ERR, scmd, "Failed to map DMA buffer for command\n");
1724848c7085STyrel Datwyler 		return sg_mapped;
1725848c7085STyrel Datwyler 	}
1726848c7085STyrel Datwyler 
1727848c7085STyrel Datwyler 	if (scmd->sc_data_direction == DMA_TO_DEVICE) {
1728848c7085STyrel Datwyler 		vfc_cmd->flags |= cpu_to_be16(IBMVFC_WRITE);
1729848c7085STyrel Datwyler 		iu->add_cdb_len |= IBMVFC_WRDATA;
1730848c7085STyrel Datwyler 	} else {
1731848c7085STyrel Datwyler 		vfc_cmd->flags |= cpu_to_be16(IBMVFC_READ);
1732848c7085STyrel Datwyler 		iu->add_cdb_len |= IBMVFC_RDDATA;
1733848c7085STyrel Datwyler 	}
1734848c7085STyrel Datwyler 
1735848c7085STyrel Datwyler 	if (sg_mapped == 1) {
1736848c7085STyrel Datwyler 		ibmvfc_map_sg_list(scmd, sg_mapped, data);
1737848c7085STyrel Datwyler 		return 0;
1738848c7085STyrel Datwyler 	}
1739848c7085STyrel Datwyler 
1740848c7085STyrel Datwyler 	vfc_cmd->flags |= cpu_to_be16(IBMVFC_SCATTERLIST);
1741848c7085STyrel Datwyler 
1742848c7085STyrel Datwyler 	if (!evt->ext_list) {
1743848c7085STyrel Datwyler 		evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC,
1744848c7085STyrel Datwyler 					       &evt->ext_list_token);
1745848c7085STyrel Datwyler 
1746848c7085STyrel Datwyler 		if (!evt->ext_list) {
1747848c7085STyrel Datwyler 			scsi_dma_unmap(scmd);
1748848c7085STyrel Datwyler 			if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL)
1749848c7085STyrel Datwyler 				scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n");
1750848c7085STyrel Datwyler 			return -ENOMEM;
1751848c7085STyrel Datwyler 		}
1752848c7085STyrel Datwyler 	}
1753848c7085STyrel Datwyler 
1754848c7085STyrel Datwyler 	ibmvfc_map_sg_list(scmd, sg_mapped, evt->ext_list);
1755848c7085STyrel Datwyler 
1756848c7085STyrel Datwyler 	data->va = cpu_to_be64(evt->ext_list_token);
1757848c7085STyrel Datwyler 	data->len = cpu_to_be32(sg_mapped * sizeof(struct srp_direct_buf));
1758848c7085STyrel Datwyler 	data->key = 0;
1759848c7085STyrel Datwyler 	return 0;
1760848c7085STyrel Datwyler }
1761848c7085STyrel Datwyler 
1762848c7085STyrel Datwyler /**
1763848c7085STyrel Datwyler  * ibmvfc_timeout - Internal command timeout handler
1764848c7085STyrel Datwyler  * @t:	struct ibmvfc_event that timed out
1765848c7085STyrel Datwyler  *
1766848c7085STyrel Datwyler  * Called when an internally generated command times out
1767848c7085STyrel Datwyler  **/
ibmvfc_timeout(struct timer_list * t)1768848c7085STyrel Datwyler static void ibmvfc_timeout(struct timer_list *t)
1769848c7085STyrel Datwyler {
1770848c7085STyrel Datwyler 	struct ibmvfc_event *evt = timer_container_of(evt, t, timer);
1771848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
1772848c7085STyrel Datwyler 	dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt);
1773848c7085STyrel Datwyler 	ibmvfc_reset_host(vhost);
1774848c7085STyrel Datwyler }
1775848c7085STyrel Datwyler 
1776848c7085STyrel Datwyler /**
1777848c7085STyrel Datwyler  * ibmvfc_send_event - Transforms event to u64 array and calls send_crq()
1778848c7085STyrel Datwyler  * @evt:		event to be sent
1779848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
1780848c7085STyrel Datwyler  * @timeout:	timeout in seconds - 0 means do not time command
1781848c7085STyrel Datwyler  *
1782848c7085STyrel Datwyler  * Returns the value returned from ibmvfc_send_crq(). (Zero for success)
1783848c7085STyrel Datwyler  **/
ibmvfc_send_event(struct ibmvfc_event * evt,struct ibmvfc_host * vhost,unsigned long timeout)17846fac8df9STyrel Datwyler int ibmvfc_send_event(struct ibmvfc_event *evt,
1785848c7085STyrel Datwyler 			     struct ibmvfc_host *vhost, unsigned long timeout)
1786848c7085STyrel Datwyler {
1787848c7085STyrel Datwyler 	__be64 *crq_as_u64 = (__be64 *) &evt->crq;
1788848c7085STyrel Datwyler 	unsigned long flags;
1789848c7085STyrel Datwyler 	int rc;
1790848c7085STyrel Datwyler 
1791848c7085STyrel Datwyler 	/* Copy the IU into the transfer area */
1792848c7085STyrel Datwyler 	*evt->xfer_iu = evt->iu;
1793848c7085STyrel Datwyler 	if (evt->crq.format == IBMVFC_CMD_FORMAT)
1794848c7085STyrel Datwyler 		evt->xfer_iu->cmd.tag = cpu_to_be64((u64)evt);
1795848c7085STyrel Datwyler 	else if (evt->crq.format == IBMVFC_MAD_FORMAT)
1796848c7085STyrel Datwyler 		evt->xfer_iu->mad_common.tag = cpu_to_be64((u64)evt);
1797848c7085STyrel Datwyler 	else
1798848c7085STyrel Datwyler 		BUG();
1799848c7085STyrel Datwyler 
1800848c7085STyrel Datwyler 	timer_setup(&evt->timer, ibmvfc_timeout, 0);
1801848c7085STyrel Datwyler 
1802848c7085STyrel Datwyler 	if (timeout) {
1803848c7085STyrel Datwyler 		evt->timer.expires = jiffies + (timeout * HZ);
1804848c7085STyrel Datwyler 		add_timer(&evt->timer);
1805848c7085STyrel Datwyler 	}
1806848c7085STyrel Datwyler 
1807848c7085STyrel Datwyler 	spin_lock_irqsave(&evt->queue->l_lock, flags);
1808848c7085STyrel Datwyler 	list_add_tail(&evt->queue_list, &evt->queue->sent);
1809848c7085STyrel Datwyler 	atomic_set(&evt->active, 1);
1810848c7085STyrel Datwyler 
1811848c7085STyrel Datwyler 	mb();
1812848c7085STyrel Datwyler 
1813848c7085STyrel Datwyler 	if (evt->queue->fmt == IBMVFC_SUB_CRQ_FMT)
1814848c7085STyrel Datwyler 		rc = ibmvfc_send_sub_crq(vhost,
1815848c7085STyrel Datwyler 					 evt->queue->vios_cookie,
1816848c7085STyrel Datwyler 					 be64_to_cpu(crq_as_u64[0]),
1817848c7085STyrel Datwyler 					 be64_to_cpu(crq_as_u64[1]),
1818848c7085STyrel Datwyler 					 0, 0);
1819848c7085STyrel Datwyler 	else
1820848c7085STyrel Datwyler 		rc = ibmvfc_send_crq(vhost, be64_to_cpu(crq_as_u64[0]),
1821848c7085STyrel Datwyler 				     be64_to_cpu(crq_as_u64[1]));
1822848c7085STyrel Datwyler 
1823848c7085STyrel Datwyler 	if (rc) {
1824848c7085STyrel Datwyler 		atomic_set(&evt->active, 0);
1825848c7085STyrel Datwyler 		list_del(&evt->queue_list);
1826848c7085STyrel Datwyler 		spin_unlock_irqrestore(&evt->queue->l_lock, flags);
1827848c7085STyrel Datwyler 		timer_delete(&evt->timer);
1828848c7085STyrel Datwyler 
1829848c7085STyrel Datwyler 		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
1830848c7085STyrel Datwyler 		 * Firmware will send a CRQ with a transport event (0xFF) to
1831848c7085STyrel Datwyler 		 * tell this client what has happened to the transport. This
1832848c7085STyrel Datwyler 		 * will be handled in ibmvfc_handle_crq()
1833848c7085STyrel Datwyler 		 */
1834848c7085STyrel Datwyler 		if (rc == H_CLOSED) {
1835848c7085STyrel Datwyler 			if (printk_ratelimit())
1836848c7085STyrel Datwyler 				dev_warn(vhost->dev, "Send warning. Receive queue closed, will retry.\n");
1837848c7085STyrel Datwyler 			if (evt->cmnd)
1838848c7085STyrel Datwyler 				scsi_dma_unmap(evt->cmnd);
1839848c7085STyrel Datwyler 			ibmvfc_free_event(evt);
1840848c7085STyrel Datwyler 			return SCSI_MLQUEUE_HOST_BUSY;
1841848c7085STyrel Datwyler 		}
1842848c7085STyrel Datwyler 
1843848c7085STyrel Datwyler 		dev_err(vhost->dev, "Send error (rc=%d)\n", rc);
1844848c7085STyrel Datwyler 		if (evt->cmnd) {
1845848c7085STyrel Datwyler 			evt->cmnd->result = DID_ERROR << 16;
18464857949bSTyrel Datwyler 			evt->done = ibmvfc_vfc_eh_done;
18474857949bSTyrel Datwyler 		} else if (evt->fcp_req || evt->ls_req) {
18484857949bSTyrel Datwyler 			evt->done = ibmvfc_vfc_eh_done;
1849848c7085STyrel Datwyler 		} else {
1850848c7085STyrel Datwyler 			evt->xfer_iu->mad_common.status = cpu_to_be16(IBMVFC_MAD_CRQ_ERROR);
1851848c7085STyrel Datwyler 			evt->done = evt->_done;
1852848c7085STyrel Datwyler 		}
1853848c7085STyrel Datwyler 
1854848c7085STyrel Datwyler 		evt->done(evt);
1855848c7085STyrel Datwyler 	} else {
1856848c7085STyrel Datwyler 		spin_unlock_irqrestore(&evt->queue->l_lock, flags);
1857848c7085STyrel Datwyler 		ibmvfc_trc_start(evt);
1858848c7085STyrel Datwyler 	}
1859848c7085STyrel Datwyler 
1860848c7085STyrel Datwyler 	return 0;
1861848c7085STyrel Datwyler }
1862848c7085STyrel Datwyler 
1863848c7085STyrel Datwyler /**
1864848c7085STyrel Datwyler  * ibmvfc_log_error - Log an error for the failed command if appropriate
1865848c7085STyrel Datwyler  * @evt:	ibmvfc event to log
1866848c7085STyrel Datwyler  *
1867848c7085STyrel Datwyler  **/
ibmvfc_log_error(struct ibmvfc_event * evt)1868848c7085STyrel Datwyler static void ibmvfc_log_error(struct ibmvfc_event *evt)
1869848c7085STyrel Datwyler {
1870848c7085STyrel Datwyler 	struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd;
1871848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
1872848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd);
1873848c7085STyrel Datwyler 	struct scsi_cmnd *cmnd = evt->cmnd;
1874848c7085STyrel Datwyler 	const char *err = unknown_error;
1875848c7085STyrel Datwyler 	int index = ibmvfc_get_err_index(be16_to_cpu(vfc_cmd->status), be16_to_cpu(vfc_cmd->error));
1876848c7085STyrel Datwyler 	int logerr = 0;
1877848c7085STyrel Datwyler 	int rsp_code = 0;
1878848c7085STyrel Datwyler 
1879848c7085STyrel Datwyler 	if (index >= 0) {
1880848c7085STyrel Datwyler 		logerr = cmd_status[index].log;
1881848c7085STyrel Datwyler 		err = cmd_status[index].name;
1882848c7085STyrel Datwyler 	}
1883848c7085STyrel Datwyler 
1884848c7085STyrel Datwyler 	if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1)))
1885848c7085STyrel Datwyler 		return;
1886848c7085STyrel Datwyler 
1887848c7085STyrel Datwyler 	if (rsp->flags & FCP_RSP_LEN_VALID)
1888848c7085STyrel Datwyler 		rsp_code = rsp->data.info.rsp_code;
1889848c7085STyrel Datwyler 
1890848c7085STyrel Datwyler 	scmd_printk(KERN_ERR, cmnd, "Command (%02X) : %s (%x:%x) "
1891848c7085STyrel Datwyler 		    "flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n",
1892848c7085STyrel Datwyler 		    cmnd->cmnd[0], err, be16_to_cpu(vfc_cmd->status), be16_to_cpu(vfc_cmd->error),
1893848c7085STyrel Datwyler 		    rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status);
1894848c7085STyrel Datwyler }
1895848c7085STyrel Datwyler 
1896848c7085STyrel Datwyler /**
1897848c7085STyrel Datwyler  * ibmvfc_relogin - Log back into the specified device
1898848c7085STyrel Datwyler  * @sdev:	scsi device struct
1899848c7085STyrel Datwyler  *
1900848c7085STyrel Datwyler  **/
ibmvfc_scsi_relogin(struct scsi_device * sdev)1901e0fca728STyrel Datwyler static void ibmvfc_scsi_relogin(struct scsi_device *sdev)
1902848c7085STyrel Datwyler {
1903848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
1904848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
1905848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
1906848c7085STyrel Datwyler 	unsigned long flags;
1907848c7085STyrel Datwyler 
1908848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
1909848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
1910848c7085STyrel Datwyler 		if (rport == tgt->rport) {
1911848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
1912848c7085STyrel Datwyler 			break;
1913848c7085STyrel Datwyler 		}
1914848c7085STyrel Datwyler 	}
1915848c7085STyrel Datwyler 
1916848c7085STyrel Datwyler 	ibmvfc_reinit_host(vhost);
1917848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
1918848c7085STyrel Datwyler }
1919848c7085STyrel Datwyler 
1920848c7085STyrel Datwyler /**
1921848c7085STyrel Datwyler  * ibmvfc_scsi_done - Handle responses from commands
1922848c7085STyrel Datwyler  * @evt:	ibmvfc event to be handled
1923848c7085STyrel Datwyler  *
1924848c7085STyrel Datwyler  * Used as a callback when sending scsi cmds.
1925848c7085STyrel Datwyler  **/
ibmvfc_scsi_done(struct ibmvfc_event * evt)1926848c7085STyrel Datwyler static void ibmvfc_scsi_done(struct ibmvfc_event *evt)
1927848c7085STyrel Datwyler {
1928848c7085STyrel Datwyler 	struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd;
1929848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(evt->vhost, vfc_cmd);
1930848c7085STyrel Datwyler 	struct scsi_cmnd *cmnd = evt->cmnd;
1931848c7085STyrel Datwyler 	u32 rsp_len = 0;
1932848c7085STyrel Datwyler 	u32 sense_len = be32_to_cpu(rsp->fcp_sense_len);
1933848c7085STyrel Datwyler 
1934848c7085STyrel Datwyler 	if (cmnd) {
1935848c7085STyrel Datwyler 		if (be16_to_cpu(vfc_cmd->response_flags) & IBMVFC_ADAPTER_RESID_VALID)
1936848c7085STyrel Datwyler 			scsi_set_resid(cmnd, be32_to_cpu(vfc_cmd->adapter_resid));
1937848c7085STyrel Datwyler 		else if (rsp->flags & FCP_RESID_UNDER)
1938848c7085STyrel Datwyler 			scsi_set_resid(cmnd, be32_to_cpu(rsp->fcp_resid));
1939848c7085STyrel Datwyler 		else
1940848c7085STyrel Datwyler 			scsi_set_resid(cmnd, 0);
1941848c7085STyrel Datwyler 
1942848c7085STyrel Datwyler 		if (vfc_cmd->status) {
1943848c7085STyrel Datwyler 			cmnd->result = ibmvfc_get_err_result(evt->vhost, vfc_cmd);
1944848c7085STyrel Datwyler 
1945848c7085STyrel Datwyler 			if (rsp->flags & FCP_RSP_LEN_VALID)
1946848c7085STyrel Datwyler 				rsp_len = be32_to_cpu(rsp->fcp_rsp_len);
1947848c7085STyrel Datwyler 			if ((sense_len + rsp_len) > SCSI_SENSE_BUFFERSIZE)
1948848c7085STyrel Datwyler 				sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len;
1949848c7085STyrel Datwyler 			if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8)
1950848c7085STyrel Datwyler 				memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len);
1951848c7085STyrel Datwyler 			if ((be16_to_cpu(vfc_cmd->status) & IBMVFC_VIOS_FAILURE) &&
1952848c7085STyrel Datwyler 			    (be16_to_cpu(vfc_cmd->error) == IBMVFC_PLOGI_REQUIRED))
1953e0fca728STyrel Datwyler 				ibmvfc_scsi_relogin(cmnd->device);
1954848c7085STyrel Datwyler 
1955848c7085STyrel Datwyler 			if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER)))
1956848c7085STyrel Datwyler 				cmnd->result = (DID_ERROR << 16);
1957848c7085STyrel Datwyler 
1958848c7085STyrel Datwyler 			ibmvfc_log_error(evt);
1959848c7085STyrel Datwyler 		}
1960848c7085STyrel Datwyler 
1961848c7085STyrel Datwyler 		if (!cmnd->result &&
1962848c7085STyrel Datwyler 		    (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) < cmnd->underflow))
1963848c7085STyrel Datwyler 			cmnd->result = (DID_ERROR << 16);
1964848c7085STyrel Datwyler 
1965848c7085STyrel Datwyler 		scsi_dma_unmap(cmnd);
1966848c7085STyrel Datwyler 		scsi_done(cmnd);
1967848c7085STyrel Datwyler 	}
1968848c7085STyrel Datwyler 
1969848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
1970848c7085STyrel Datwyler }
1971848c7085STyrel Datwyler 
1972848c7085STyrel Datwyler /**
1973848c7085STyrel Datwyler  * ibmvfc_host_chkready - Check if the host can accept commands
1974848c7085STyrel Datwyler  * @vhost:	 struct ibmvfc host
1975848c7085STyrel Datwyler  *
1976848c7085STyrel Datwyler  * Returns:
1977848c7085STyrel Datwyler  *	1 if host can accept command / 0 if not
1978848c7085STyrel Datwyler  **/
ibmvfc_host_chkready(struct ibmvfc_host * vhost)1979848c7085STyrel Datwyler static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost)
1980848c7085STyrel Datwyler {
1981848c7085STyrel Datwyler 	int result = 0;
1982848c7085STyrel Datwyler 
1983848c7085STyrel Datwyler 	switch (vhost->state) {
1984848c7085STyrel Datwyler 	case IBMVFC_LINK_DEAD:
1985848c7085STyrel Datwyler 	case IBMVFC_HOST_OFFLINE:
1986848c7085STyrel Datwyler 		result = DID_NO_CONNECT << 16;
1987848c7085STyrel Datwyler 		break;
1988848c7085STyrel Datwyler 	case IBMVFC_NO_CRQ:
1989848c7085STyrel Datwyler 	case IBMVFC_INITIALIZING:
1990848c7085STyrel Datwyler 	case IBMVFC_HALTED:
1991848c7085STyrel Datwyler 	case IBMVFC_LINK_DOWN:
1992848c7085STyrel Datwyler 		result = DID_REQUEUE << 16;
1993848c7085STyrel Datwyler 		break;
1994848c7085STyrel Datwyler 	case IBMVFC_ACTIVE:
1995848c7085STyrel Datwyler 		result = 0;
1996848c7085STyrel Datwyler 		break;
1997848c7085STyrel Datwyler 	}
1998848c7085STyrel Datwyler 
1999848c7085STyrel Datwyler 	return result;
2000848c7085STyrel Datwyler }
2001848c7085STyrel Datwyler 
ibmvfc_init_vfc_cmd(struct ibmvfc_event * evt,struct scsi_device * sdev)2002848c7085STyrel Datwyler static struct ibmvfc_cmd *ibmvfc_init_vfc_cmd(struct ibmvfc_event *evt, struct scsi_device *sdev)
2003848c7085STyrel Datwyler {
2004848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
2005848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
2006848c7085STyrel Datwyler 	struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd;
2007848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd);
2008848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *rsp = ibmvfc_get_fcp_rsp(vhost, vfc_cmd);
2009848c7085STyrel Datwyler 	size_t offset;
2010848c7085STyrel Datwyler 
2011848c7085STyrel Datwyler 	memset(vfc_cmd, 0, sizeof(*vfc_cmd));
2012ecc03d95STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NVMEOF))
2013ecc03d95STyrel Datwyler 		offset = offsetof(struct ibmvfc_cmd, v3scsi.rsp);
2014ecc03d95STyrel Datwyler 	else if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN))
2015848c7085STyrel Datwyler 		offset = offsetof(struct ibmvfc_cmd, v2.rsp);
2016ecc03d95STyrel Datwyler 	else
2017848c7085STyrel Datwyler 		offset = offsetof(struct ibmvfc_cmd, v1.rsp);
2018ecc03d95STyrel Datwyler 	vfc_cmd->target_wwpn = cpu_to_be64(rport->port_name);
2019848c7085STyrel Datwyler 	vfc_cmd->resp.va = cpu_to_be64(be64_to_cpu(evt->crq.ioba) + offset);
2020848c7085STyrel Datwyler 	vfc_cmd->resp.len = cpu_to_be32(sizeof(*rsp));
2021848c7085STyrel Datwyler 	vfc_cmd->frame_type = cpu_to_be32(IBMVFC_SCSI_FCP_TYPE);
2022848c7085STyrel Datwyler 	vfc_cmd->payload_len = cpu_to_be32(sizeof(*iu));
2023848c7085STyrel Datwyler 	vfc_cmd->resp_len = cpu_to_be32(sizeof(*rsp));
2024848c7085STyrel Datwyler 	vfc_cmd->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata);
2025848c7085STyrel Datwyler 	vfc_cmd->tgt_scsi_id = cpu_to_be64(rport->port_id);
2026848c7085STyrel Datwyler 	int_to_scsilun(sdev->lun, &iu->lun);
2027848c7085STyrel Datwyler 
2028848c7085STyrel Datwyler 	return vfc_cmd;
2029848c7085STyrel Datwyler }
2030848c7085STyrel Datwyler 
2031848c7085STyrel Datwyler /**
2032848c7085STyrel Datwyler  * ibmvfc_queuecommand - The queuecommand function of the scsi template
2033848c7085STyrel Datwyler  * @shost:	scsi host struct
2034848c7085STyrel Datwyler  * @cmnd:	struct scsi_cmnd to be executed
2035848c7085STyrel Datwyler  *
2036848c7085STyrel Datwyler  * Returns:
2037848c7085STyrel Datwyler  *	0 on success / other on failure
2038848c7085STyrel Datwyler  **/
ibmvfc_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * cmnd)2039848c7085STyrel Datwyler static enum scsi_qc_status ibmvfc_queuecommand(struct Scsi_Host *shost,
2040848c7085STyrel Datwyler 					       struct scsi_cmnd *cmnd)
2041848c7085STyrel Datwyler {
2042848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
2043848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
2044848c7085STyrel Datwyler 	struct ibmvfc_cmd *vfc_cmd;
2045848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu;
2046848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
2047848c7085STyrel Datwyler 	u32 tag_and_hwq = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
2048848c7085STyrel Datwyler 	u16 hwq = blk_mq_unique_tag_to_hwq(tag_and_hwq);
2049848c7085STyrel Datwyler 	u16 scsi_channel;
2050848c7085STyrel Datwyler 	int rc;
2051848c7085STyrel Datwyler 
2052848c7085STyrel Datwyler 	if (unlikely((rc = fc_remote_port_chkready(rport))) ||
2053848c7085STyrel Datwyler 	    unlikely((rc = ibmvfc_host_chkready(vhost)))) {
2054848c7085STyrel Datwyler 		cmnd->result = rc;
2055848c7085STyrel Datwyler 		scsi_done(cmnd);
2056848c7085STyrel Datwyler 		return 0;
2057848c7085STyrel Datwyler 	}
2058848c7085STyrel Datwyler 
2059848c7085STyrel Datwyler 	cmnd->result = (DID_OK << 16);
2060848c7085STyrel Datwyler 	if (vhost->using_channels) {
2061848c7085STyrel Datwyler 		scsi_channel = hwq % vhost->scsi_scrqs.active_queues;
2062848c7085STyrel Datwyler 		evt = ibmvfc_get_event(&vhost->scsi_scrqs.scrqs[scsi_channel]);
2063848c7085STyrel Datwyler 		if (!evt)
2064848c7085STyrel Datwyler 			return SCSI_MLQUEUE_HOST_BUSY;
2065848c7085STyrel Datwyler 
2066848c7085STyrel Datwyler 		evt->hwq = hwq % vhost->scsi_scrqs.active_queues;
2067848c7085STyrel Datwyler 	} else {
2068848c7085STyrel Datwyler 		evt = ibmvfc_get_event(&vhost->crq);
2069848c7085STyrel Datwyler 		if (!evt)
2070848c7085STyrel Datwyler 			return SCSI_MLQUEUE_HOST_BUSY;
2071848c7085STyrel Datwyler 	}
2072848c7085STyrel Datwyler 
2073848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT);
2074848c7085STyrel Datwyler 	evt->cmnd = cmnd;
2075848c7085STyrel Datwyler 
2076848c7085STyrel Datwyler 	vfc_cmd = ibmvfc_init_vfc_cmd(evt, cmnd->device);
2077848c7085STyrel Datwyler 	iu = ibmvfc_get_fcp_iu(vhost, vfc_cmd);
2078848c7085STyrel Datwyler 
2079848c7085STyrel Datwyler 	iu->xfer_len = cpu_to_be32(scsi_bufflen(cmnd));
2080848c7085STyrel Datwyler 	memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
2081848c7085STyrel Datwyler 
2082848c7085STyrel Datwyler 	if (cmnd->flags & SCMD_TAGGED) {
2083848c7085STyrel Datwyler 		vfc_cmd->task_tag = cpu_to_be64(scsi_cmd_to_rq(cmnd)->tag);
2084848c7085STyrel Datwyler 		iu->pri_task_attr = IBMVFC_SIMPLE_TASK;
2085848c7085STyrel Datwyler 	}
2086848c7085STyrel Datwyler 
2087848c7085STyrel Datwyler 	vfc_cmd->correlation = cpu_to_be64((u64)evt);
2088848c7085STyrel Datwyler 
2089848c7085STyrel Datwyler 	if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev))))
2090848c7085STyrel Datwyler 		return ibmvfc_send_event(evt, vhost, 0);
2091848c7085STyrel Datwyler 
2092848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2093848c7085STyrel Datwyler 	if (rc == -ENOMEM)
2094848c7085STyrel Datwyler 		return SCSI_MLQUEUE_HOST_BUSY;
2095848c7085STyrel Datwyler 
2096848c7085STyrel Datwyler 	if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL)
2097848c7085STyrel Datwyler 		scmd_printk(KERN_ERR, cmnd,
2098848c7085STyrel Datwyler 			    "Failed to map DMA buffer for command. rc=%d\n", rc);
2099848c7085STyrel Datwyler 
2100848c7085STyrel Datwyler 	cmnd->result = DID_ERROR << 16;
2101848c7085STyrel Datwyler 	scsi_done(cmnd);
2102848c7085STyrel Datwyler 	return 0;
2103848c7085STyrel Datwyler }
2104848c7085STyrel Datwyler 
2105848c7085STyrel Datwyler /**
2106848c7085STyrel Datwyler  * ibmvfc_sync_completion - Signal that a synchronous command has completed
2107848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2108848c7085STyrel Datwyler  *
2109848c7085STyrel Datwyler  **/
ibmvfc_sync_completion(struct ibmvfc_event * evt)2110848c7085STyrel Datwyler static void ibmvfc_sync_completion(struct ibmvfc_event *evt)
2111848c7085STyrel Datwyler {
2112848c7085STyrel Datwyler 	/* copy the response back */
2113848c7085STyrel Datwyler 	if (evt->sync_iu)
2114848c7085STyrel Datwyler 		*evt->sync_iu = *evt->xfer_iu;
2115848c7085STyrel Datwyler 
2116848c7085STyrel Datwyler 	complete(&evt->comp);
2117848c7085STyrel Datwyler }
2118848c7085STyrel Datwyler 
2119848c7085STyrel Datwyler /**
2120848c7085STyrel Datwyler  * ibmvfc_bsg_timeout_done - Completion handler for cancelling BSG commands
2121848c7085STyrel Datwyler  * @evt:	struct ibmvfc_event
2122848c7085STyrel Datwyler  *
2123848c7085STyrel Datwyler  **/
ibmvfc_bsg_timeout_done(struct ibmvfc_event * evt)2124848c7085STyrel Datwyler static void ibmvfc_bsg_timeout_done(struct ibmvfc_event *evt)
2125848c7085STyrel Datwyler {
2126848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
2127848c7085STyrel Datwyler 
2128848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2129848c7085STyrel Datwyler 	vhost->aborting_passthru = 0;
2130848c7085STyrel Datwyler 	dev_info(vhost->dev, "Passthru command cancelled\n");
2131848c7085STyrel Datwyler }
2132848c7085STyrel Datwyler 
2133848c7085STyrel Datwyler /**
2134848c7085STyrel Datwyler  * ibmvfc_bsg_timeout - Handle a BSG timeout
2135848c7085STyrel Datwyler  * @job:	struct bsg_job that timed out
2136848c7085STyrel Datwyler  *
2137848c7085STyrel Datwyler  * Returns:
2138848c7085STyrel Datwyler  *	0 on success / other on failure
2139848c7085STyrel Datwyler  **/
ibmvfc_bsg_timeout(struct bsg_job * job)2140848c7085STyrel Datwyler static int ibmvfc_bsg_timeout(struct bsg_job *job)
2141848c7085STyrel Datwyler {
2142848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(fc_bsg_to_shost(job));
2143848c7085STyrel Datwyler 	unsigned long port_id = (unsigned long)job->dd_data;
2144848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
2145848c7085STyrel Datwyler 	struct ibmvfc_tmf *tmf;
2146848c7085STyrel Datwyler 	unsigned long flags;
2147848c7085STyrel Datwyler 	int rc;
2148848c7085STyrel Datwyler 
2149848c7085STyrel Datwyler 	ENTER;
2150848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2151848c7085STyrel Datwyler 	if (vhost->aborting_passthru || vhost->state != IBMVFC_ACTIVE) {
2152848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
2153848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2154848c7085STyrel Datwyler 		return 0;
2155848c7085STyrel Datwyler 	}
2156848c7085STyrel Datwyler 
2157848c7085STyrel Datwyler 	vhost->aborting_passthru = 1;
2158848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
2159848c7085STyrel Datwyler 	if (!evt) {
2160848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2161848c7085STyrel Datwyler 		return -ENOMEM;
2162848c7085STyrel Datwyler 	}
2163848c7085STyrel Datwyler 
2164848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_bsg_timeout_done, IBMVFC_MAD_FORMAT);
2165848c7085STyrel Datwyler 
2166848c7085STyrel Datwyler 	tmf = &evt->iu.tmf;
2167848c7085STyrel Datwyler 	memset(tmf, 0, sizeof(*tmf));
2168848c7085STyrel Datwyler 	tmf->common.version = cpu_to_be32(1);
2169848c7085STyrel Datwyler 	tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD);
2170848c7085STyrel Datwyler 	tmf->common.length = cpu_to_be16(sizeof(*tmf));
2171848c7085STyrel Datwyler 	tmf->scsi_id = cpu_to_be64(port_id);
2172848c7085STyrel Datwyler 	tmf->cancel_key = cpu_to_be32(IBMVFC_PASSTHRU_CANCEL_KEY);
2173848c7085STyrel Datwyler 	tmf->my_cancel_key = cpu_to_be32(IBMVFC_INTERNAL_CANCEL_KEY);
2174848c7085STyrel Datwyler 	rc = ibmvfc_send_event(evt, vhost, default_timeout);
2175848c7085STyrel Datwyler 
2176848c7085STyrel Datwyler 	if (rc != 0) {
2177848c7085STyrel Datwyler 		vhost->aborting_passthru = 0;
2178848c7085STyrel Datwyler 		dev_err(vhost->dev, "Failed to send cancel event. rc=%d\n", rc);
2179848c7085STyrel Datwyler 		rc = -EIO;
2180848c7085STyrel Datwyler 	} else
2181848c7085STyrel Datwyler 		dev_info(vhost->dev, "Cancelling passthru command to port id 0x%lx\n",
2182848c7085STyrel Datwyler 			 port_id);
2183848c7085STyrel Datwyler 
2184848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2185848c7085STyrel Datwyler 
2186848c7085STyrel Datwyler 	LEAVE;
2187848c7085STyrel Datwyler 	return rc;
2188848c7085STyrel Datwyler }
2189848c7085STyrel Datwyler 
2190848c7085STyrel Datwyler /**
2191848c7085STyrel Datwyler  * ibmvfc_bsg_plogi - PLOGI into a target to handle a BSG command
2192848c7085STyrel Datwyler  * @vhost:		struct ibmvfc_host to send command
2193848c7085STyrel Datwyler  * @port_id:	port ID to send command
2194848c7085STyrel Datwyler  *
2195848c7085STyrel Datwyler  * Returns:
2196848c7085STyrel Datwyler  *	0 on success / other on failure
2197848c7085STyrel Datwyler  **/
ibmvfc_bsg_plogi(struct ibmvfc_host * vhost,unsigned int port_id)2198848c7085STyrel Datwyler static int ibmvfc_bsg_plogi(struct ibmvfc_host *vhost, unsigned int port_id)
2199848c7085STyrel Datwyler {
2200848c7085STyrel Datwyler 	struct ibmvfc_port_login *plogi;
2201848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
2202848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
2203848c7085STyrel Datwyler 	union ibmvfc_iu rsp_iu;
2204848c7085STyrel Datwyler 	unsigned long flags;
2205848c7085STyrel Datwyler 	int rc = 0, issue_login = 1;
2206848c7085STyrel Datwyler 
2207848c7085STyrel Datwyler 	ENTER;
2208848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2209848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
2210848c7085STyrel Datwyler 		if (tgt->scsi_id == port_id) {
2211848c7085STyrel Datwyler 			issue_login = 0;
2212848c7085STyrel Datwyler 			break;
2213848c7085STyrel Datwyler 		}
2214848c7085STyrel Datwyler 	}
2215848c7085STyrel Datwyler 
2216848c7085STyrel Datwyler 	if (!issue_login)
2217848c7085STyrel Datwyler 		goto unlock_out;
2218848c7085STyrel Datwyler 	if (unlikely((rc = ibmvfc_host_chkready(vhost))))
2219848c7085STyrel Datwyler 		goto unlock_out;
2220848c7085STyrel Datwyler 
2221848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
2222848c7085STyrel Datwyler 	if (!evt) {
2223848c7085STyrel Datwyler 		rc = -ENOMEM;
2224848c7085STyrel Datwyler 		goto unlock_out;
2225848c7085STyrel Datwyler 	}
2226848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
2227848c7085STyrel Datwyler 	plogi = &evt->iu.plogi;
2228848c7085STyrel Datwyler 	memset(plogi, 0, sizeof(*plogi));
2229848c7085STyrel Datwyler 	plogi->common.version = cpu_to_be32(1);
2230848c7085STyrel Datwyler 	plogi->common.opcode = cpu_to_be32(IBMVFC_PORT_LOGIN);
2231848c7085STyrel Datwyler 	plogi->common.length = cpu_to_be16(sizeof(*plogi));
2232848c7085STyrel Datwyler 	plogi->scsi_id = cpu_to_be64(port_id);
2233848c7085STyrel Datwyler 	evt->sync_iu = &rsp_iu;
2234848c7085STyrel Datwyler 	init_completion(&evt->comp);
2235848c7085STyrel Datwyler 
2236848c7085STyrel Datwyler 	rc = ibmvfc_send_event(evt, vhost, default_timeout);
2237848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2238848c7085STyrel Datwyler 
2239848c7085STyrel Datwyler 	if (rc)
2240848c7085STyrel Datwyler 		return -EIO;
2241848c7085STyrel Datwyler 
2242848c7085STyrel Datwyler 	wait_for_completion(&evt->comp);
2243848c7085STyrel Datwyler 
2244848c7085STyrel Datwyler 	if (rsp_iu.plogi.common.status)
2245848c7085STyrel Datwyler 		rc = -EIO;
2246848c7085STyrel Datwyler 
2247848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2248848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2249848c7085STyrel Datwyler unlock_out:
2250848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2251848c7085STyrel Datwyler 	LEAVE;
2252848c7085STyrel Datwyler 	return rc;
2253848c7085STyrel Datwyler }
2254848c7085STyrel Datwyler 
2255848c7085STyrel Datwyler /**
2256848c7085STyrel Datwyler  * ibmvfc_bsg_request - Handle a BSG request
2257848c7085STyrel Datwyler  * @job:	struct bsg_job to be executed
2258848c7085STyrel Datwyler  *
2259848c7085STyrel Datwyler  * Returns:
2260848c7085STyrel Datwyler  *	0 on success / other on failure
2261848c7085STyrel Datwyler  **/
ibmvfc_bsg_request(struct bsg_job * job)2262848c7085STyrel Datwyler static int ibmvfc_bsg_request(struct bsg_job *job)
2263848c7085STyrel Datwyler {
2264848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(fc_bsg_to_shost(job));
2265848c7085STyrel Datwyler 	struct fc_rport *rport = fc_bsg_to_rport(job);
2266848c7085STyrel Datwyler 	struct ibmvfc_passthru_mad *mad;
2267848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
2268848c7085STyrel Datwyler 	union ibmvfc_iu rsp_iu;
2269848c7085STyrel Datwyler 	unsigned long flags, port_id = -1;
2270848c7085STyrel Datwyler 	struct fc_bsg_request *bsg_request = job->request;
2271848c7085STyrel Datwyler 	struct fc_bsg_reply *bsg_reply = job->reply;
2272848c7085STyrel Datwyler 	unsigned int code = bsg_request->msgcode;
2273848c7085STyrel Datwyler 	int rc = 0, req_seg, rsp_seg, issue_login = 0;
2274848c7085STyrel Datwyler 	u32 fc_flags, rsp_len;
2275848c7085STyrel Datwyler 
2276848c7085STyrel Datwyler 	ENTER;
2277848c7085STyrel Datwyler 	bsg_reply->reply_payload_rcv_len = 0;
2278848c7085STyrel Datwyler 	if (rport)
2279848c7085STyrel Datwyler 		port_id = rport->port_id;
2280848c7085STyrel Datwyler 
2281848c7085STyrel Datwyler 	switch (code) {
2282848c7085STyrel Datwyler 	case FC_BSG_HST_ELS_NOLOGIN:
2283848c7085STyrel Datwyler 		port_id = (bsg_request->rqst_data.h_els.port_id[0] << 16) |
2284848c7085STyrel Datwyler 			(bsg_request->rqst_data.h_els.port_id[1] << 8) |
2285848c7085STyrel Datwyler 			bsg_request->rqst_data.h_els.port_id[2];
2286848c7085STyrel Datwyler 		fallthrough;
2287848c7085STyrel Datwyler 	case FC_BSG_RPT_ELS:
2288848c7085STyrel Datwyler 		fc_flags = IBMVFC_FC_ELS;
2289848c7085STyrel Datwyler 		break;
2290848c7085STyrel Datwyler 	case FC_BSG_HST_CT:
2291848c7085STyrel Datwyler 		issue_login = 1;
2292848c7085STyrel Datwyler 		port_id = (bsg_request->rqst_data.h_ct.port_id[0] << 16) |
2293848c7085STyrel Datwyler 			(bsg_request->rqst_data.h_ct.port_id[1] << 8) |
2294848c7085STyrel Datwyler 			bsg_request->rqst_data.h_ct.port_id[2];
2295848c7085STyrel Datwyler 		fallthrough;
2296848c7085STyrel Datwyler 	case FC_BSG_RPT_CT:
2297848c7085STyrel Datwyler 		fc_flags = IBMVFC_FC_CT_IU;
2298848c7085STyrel Datwyler 		break;
2299848c7085STyrel Datwyler 	default:
2300848c7085STyrel Datwyler 		return -ENOTSUPP;
2301848c7085STyrel Datwyler 	}
2302848c7085STyrel Datwyler 
2303848c7085STyrel Datwyler 	if (port_id == -1)
2304848c7085STyrel Datwyler 		return -EINVAL;
2305848c7085STyrel Datwyler 	if (!mutex_trylock(&vhost->passthru_mutex))
2306848c7085STyrel Datwyler 		return -EBUSY;
2307848c7085STyrel Datwyler 
2308848c7085STyrel Datwyler 	job->dd_data = (void *)port_id;
2309848c7085STyrel Datwyler 	req_seg = dma_map_sg(vhost->dev, job->request_payload.sg_list,
2310848c7085STyrel Datwyler 			     job->request_payload.sg_cnt, DMA_TO_DEVICE);
2311848c7085STyrel Datwyler 
2312848c7085STyrel Datwyler 	if (!req_seg) {
2313848c7085STyrel Datwyler 		mutex_unlock(&vhost->passthru_mutex);
2314848c7085STyrel Datwyler 		return -ENOMEM;
2315848c7085STyrel Datwyler 	}
2316848c7085STyrel Datwyler 
2317848c7085STyrel Datwyler 	rsp_seg = dma_map_sg(vhost->dev, job->reply_payload.sg_list,
2318848c7085STyrel Datwyler 			     job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
2319848c7085STyrel Datwyler 
2320848c7085STyrel Datwyler 	if (!rsp_seg) {
2321848c7085STyrel Datwyler 		dma_unmap_sg(vhost->dev, job->request_payload.sg_list,
2322848c7085STyrel Datwyler 			     job->request_payload.sg_cnt, DMA_TO_DEVICE);
2323848c7085STyrel Datwyler 		mutex_unlock(&vhost->passthru_mutex);
2324848c7085STyrel Datwyler 		return -ENOMEM;
2325848c7085STyrel Datwyler 	}
2326848c7085STyrel Datwyler 
2327848c7085STyrel Datwyler 	if (req_seg > 1 || rsp_seg > 1) {
2328848c7085STyrel Datwyler 		rc = -EINVAL;
2329848c7085STyrel Datwyler 		goto out;
2330848c7085STyrel Datwyler 	}
2331848c7085STyrel Datwyler 
2332848c7085STyrel Datwyler 	if (issue_login)
2333848c7085STyrel Datwyler 		rc = ibmvfc_bsg_plogi(vhost, port_id);
2334848c7085STyrel Datwyler 
2335848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2336848c7085STyrel Datwyler 
2337848c7085STyrel Datwyler 	if (unlikely(rc || (rport && (rc = fc_remote_port_chkready(rport)))) ||
2338848c7085STyrel Datwyler 	    unlikely((rc = ibmvfc_host_chkready(vhost)))) {
2339848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2340848c7085STyrel Datwyler 		goto out;
2341848c7085STyrel Datwyler 	}
2342848c7085STyrel Datwyler 
2343848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
2344848c7085STyrel Datwyler 	if (!evt) {
2345848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2346848c7085STyrel Datwyler 		rc = -ENOMEM;
2347848c7085STyrel Datwyler 		goto out;
2348848c7085STyrel Datwyler 	}
2349848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
2350848c7085STyrel Datwyler 	mad = &evt->iu.passthru;
2351848c7085STyrel Datwyler 
2352848c7085STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
2353848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
2354848c7085STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_PASSTHRU);
2355848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu));
2356848c7085STyrel Datwyler 
2357848c7085STyrel Datwyler 	mad->cmd_ioba.va = cpu_to_be64(be64_to_cpu(evt->crq.ioba) +
2358848c7085STyrel Datwyler 		offsetof(struct ibmvfc_passthru_mad, iu));
2359848c7085STyrel Datwyler 	mad->cmd_ioba.len = cpu_to_be32(sizeof(mad->iu));
2360848c7085STyrel Datwyler 
2361848c7085STyrel Datwyler 	mad->iu.cmd_len = cpu_to_be32(job->request_payload.payload_len);
2362848c7085STyrel Datwyler 	mad->iu.rsp_len = cpu_to_be32(job->reply_payload.payload_len);
2363848c7085STyrel Datwyler 	mad->iu.flags = cpu_to_be32(fc_flags);
2364848c7085STyrel Datwyler 	mad->iu.cancel_key = cpu_to_be32(IBMVFC_PASSTHRU_CANCEL_KEY);
2365848c7085STyrel Datwyler 
2366848c7085STyrel Datwyler 	mad->iu.cmd.va = cpu_to_be64(sg_dma_address(job->request_payload.sg_list));
2367848c7085STyrel Datwyler 	mad->iu.cmd.len = cpu_to_be32(sg_dma_len(job->request_payload.sg_list));
2368848c7085STyrel Datwyler 	mad->iu.rsp.va = cpu_to_be64(sg_dma_address(job->reply_payload.sg_list));
2369848c7085STyrel Datwyler 	mad->iu.rsp.len = cpu_to_be32(sg_dma_len(job->reply_payload.sg_list));
2370848c7085STyrel Datwyler 	mad->iu.scsi_id = cpu_to_be64(port_id);
2371848c7085STyrel Datwyler 	mad->iu.tag = cpu_to_be64((u64)evt);
2372848c7085STyrel Datwyler 	rsp_len = be32_to_cpu(mad->iu.rsp.len);
2373848c7085STyrel Datwyler 
2374848c7085STyrel Datwyler 	evt->sync_iu = &rsp_iu;
2375848c7085STyrel Datwyler 	init_completion(&evt->comp);
2376848c7085STyrel Datwyler 	rc = ibmvfc_send_event(evt, vhost, 0);
2377848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2378848c7085STyrel Datwyler 
2379848c7085STyrel Datwyler 	if (rc) {
2380848c7085STyrel Datwyler 		rc = -EIO;
2381848c7085STyrel Datwyler 		goto out;
2382848c7085STyrel Datwyler 	}
2383848c7085STyrel Datwyler 
2384848c7085STyrel Datwyler 	wait_for_completion(&evt->comp);
2385848c7085STyrel Datwyler 
2386848c7085STyrel Datwyler 	if (rsp_iu.passthru.common.status)
2387848c7085STyrel Datwyler 		rc = -EIO;
2388848c7085STyrel Datwyler 	else
2389848c7085STyrel Datwyler 		bsg_reply->reply_payload_rcv_len = rsp_len;
2390848c7085STyrel Datwyler 
2391848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2392848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2393848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2394848c7085STyrel Datwyler 	bsg_reply->result = rc;
2395848c7085STyrel Datwyler 	bsg_job_done(job, bsg_reply->result,
2396848c7085STyrel Datwyler 		       bsg_reply->reply_payload_rcv_len);
2397848c7085STyrel Datwyler 	rc = 0;
2398848c7085STyrel Datwyler out:
2399848c7085STyrel Datwyler 	dma_unmap_sg(vhost->dev, job->request_payload.sg_list,
2400848c7085STyrel Datwyler 		     job->request_payload.sg_cnt, DMA_TO_DEVICE);
2401848c7085STyrel Datwyler 	dma_unmap_sg(vhost->dev, job->reply_payload.sg_list,
2402848c7085STyrel Datwyler 		     job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
2403848c7085STyrel Datwyler 	mutex_unlock(&vhost->passthru_mutex);
2404848c7085STyrel Datwyler 	LEAVE;
2405848c7085STyrel Datwyler 	return rc;
2406848c7085STyrel Datwyler }
2407848c7085STyrel Datwyler 
2408848c7085STyrel Datwyler /**
2409848c7085STyrel Datwyler  * ibmvfc_reset_device - Reset the device with the specified reset type
2410848c7085STyrel Datwyler  * @sdev:	scsi device to reset
2411848c7085STyrel Datwyler  * @type:	reset type
2412848c7085STyrel Datwyler  * @desc:	reset type description for log messages
2413848c7085STyrel Datwyler  *
2414848c7085STyrel Datwyler  * Returns:
2415848c7085STyrel Datwyler  *	0 on success / other on failure
2416848c7085STyrel Datwyler  **/
ibmvfc_reset_device(struct scsi_device * sdev,int type,char * desc)2417848c7085STyrel Datwyler static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc)
2418848c7085STyrel Datwyler {
2419848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
2420848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
2421848c7085STyrel Datwyler 	struct ibmvfc_cmd *tmf;
2422848c7085STyrel Datwyler 	struct ibmvfc_event *evt = NULL;
2423848c7085STyrel Datwyler 	union ibmvfc_iu rsp_iu;
2424848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu;
2425848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *fc_rsp = ibmvfc_get_fcp_rsp(vhost, &rsp_iu.cmd);
2426848c7085STyrel Datwyler 	int rsp_rc = -EBUSY;
2427848c7085STyrel Datwyler 	unsigned long flags;
2428848c7085STyrel Datwyler 	int rsp_code = 0;
2429848c7085STyrel Datwyler 
2430848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2431848c7085STyrel Datwyler 	if (vhost->state == IBMVFC_ACTIVE) {
2432848c7085STyrel Datwyler 		if (vhost->using_channels)
2433848c7085STyrel Datwyler 			evt = ibmvfc_get_event(&vhost->scsi_scrqs.scrqs[0]);
2434848c7085STyrel Datwyler 		else
2435848c7085STyrel Datwyler 			evt = ibmvfc_get_event(&vhost->crq);
2436848c7085STyrel Datwyler 
2437848c7085STyrel Datwyler 		if (!evt) {
2438848c7085STyrel Datwyler 			spin_unlock_irqrestore(vhost->host->host_lock, flags);
2439848c7085STyrel Datwyler 			return -ENOMEM;
2440848c7085STyrel Datwyler 		}
2441848c7085STyrel Datwyler 
2442848c7085STyrel Datwyler 		ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT);
2443848c7085STyrel Datwyler 		tmf = ibmvfc_init_vfc_cmd(evt, sdev);
2444848c7085STyrel Datwyler 		iu = ibmvfc_get_fcp_iu(vhost, tmf);
2445848c7085STyrel Datwyler 
2446848c7085STyrel Datwyler 		tmf->flags = cpu_to_be16((IBMVFC_NO_MEM_DESC | IBMVFC_TMF));
2447848c7085STyrel Datwyler 		if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN))
2448848c7085STyrel Datwyler 			tmf->target_wwpn = cpu_to_be64(rport->port_name);
2449848c7085STyrel Datwyler 		iu->tmf_flags = type;
2450848c7085STyrel Datwyler 		evt->sync_iu = &rsp_iu;
2451848c7085STyrel Datwyler 
2452848c7085STyrel Datwyler 		init_completion(&evt->comp);
2453848c7085STyrel Datwyler 		rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout);
2454848c7085STyrel Datwyler 	}
2455848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2456848c7085STyrel Datwyler 
2457848c7085STyrel Datwyler 	if (rsp_rc != 0) {
2458848c7085STyrel Datwyler 		sdev_printk(KERN_ERR, sdev, "Failed to send %s reset event. rc=%d\n",
2459848c7085STyrel Datwyler 			    desc, rsp_rc);
2460848c7085STyrel Datwyler 		return -EIO;
2461848c7085STyrel Datwyler 	}
2462848c7085STyrel Datwyler 
2463848c7085STyrel Datwyler 	sdev_printk(KERN_INFO, sdev, "Resetting %s\n", desc);
2464848c7085STyrel Datwyler 	wait_for_completion(&evt->comp);
2465848c7085STyrel Datwyler 
2466848c7085STyrel Datwyler 	if (rsp_iu.cmd.status)
2467848c7085STyrel Datwyler 		rsp_code = ibmvfc_get_err_result(vhost, &rsp_iu.cmd);
2468848c7085STyrel Datwyler 
2469848c7085STyrel Datwyler 	if (rsp_code) {
2470848c7085STyrel Datwyler 		if (fc_rsp->flags & FCP_RSP_LEN_VALID)
2471848c7085STyrel Datwyler 			rsp_code = fc_rsp->data.info.rsp_code;
2472848c7085STyrel Datwyler 
2473848c7085STyrel Datwyler 		sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) "
2474848c7085STyrel Datwyler 			    "flags: %x fcp_rsp: %x, scsi_status: %x\n", desc,
2475848c7085STyrel Datwyler 			    ibmvfc_get_cmd_error(be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error)),
2476848c7085STyrel Datwyler 			    be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error), fc_rsp->flags, rsp_code,
2477848c7085STyrel Datwyler 			    fc_rsp->scsi_status);
2478848c7085STyrel Datwyler 		rsp_rc = -EIO;
2479848c7085STyrel Datwyler 	} else
2480848c7085STyrel Datwyler 		sdev_printk(KERN_INFO, sdev, "%s reset successful\n", desc);
2481848c7085STyrel Datwyler 
2482848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2483848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2484848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2485848c7085STyrel Datwyler 	return rsp_rc;
2486848c7085STyrel Datwyler }
2487848c7085STyrel Datwyler 
2488848c7085STyrel Datwyler /**
2489848c7085STyrel Datwyler  * ibmvfc_match_rport - Match function for specified remote port
2490848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2491848c7085STyrel Datwyler  * @rport:	device to match
2492848c7085STyrel Datwyler  *
2493848c7085STyrel Datwyler  * Returns:
2494848c7085STyrel Datwyler  *	1 if event matches rport / 0 if event does not match rport
2495848c7085STyrel Datwyler  **/
ibmvfc_match_rport(struct ibmvfc_event * evt,void * rport)2496848c7085STyrel Datwyler static int ibmvfc_match_rport(struct ibmvfc_event *evt, void *rport)
2497848c7085STyrel Datwyler {
2498848c7085STyrel Datwyler 	struct fc_rport *cmd_rport;
2499848c7085STyrel Datwyler 
2500848c7085STyrel Datwyler 	if (evt->cmnd) {
2501848c7085STyrel Datwyler 		cmd_rport = starget_to_rport(scsi_target(evt->cmnd->device));
2502848c7085STyrel Datwyler 		if (cmd_rport == rport)
2503848c7085STyrel Datwyler 			return 1;
2504848c7085STyrel Datwyler 	}
2505848c7085STyrel Datwyler 	return 0;
2506848c7085STyrel Datwyler }
2507848c7085STyrel Datwyler 
2508848c7085STyrel Datwyler /**
2509848c7085STyrel Datwyler  * ibmvfc_match_target - Match function for specified target
2510848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2511848c7085STyrel Datwyler  * @device:	device to match (starget)
2512848c7085STyrel Datwyler  *
2513848c7085STyrel Datwyler  * Returns:
2514848c7085STyrel Datwyler  *	1 if event matches starget / 0 if event does not match starget
2515848c7085STyrel Datwyler  **/
ibmvfc_match_target(struct ibmvfc_event * evt,void * device)2516848c7085STyrel Datwyler static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device)
2517848c7085STyrel Datwyler {
2518848c7085STyrel Datwyler 	if (evt->cmnd && scsi_target(evt->cmnd->device) == device)
2519848c7085STyrel Datwyler 		return 1;
2520848c7085STyrel Datwyler 	return 0;
2521848c7085STyrel Datwyler }
2522848c7085STyrel Datwyler 
2523848c7085STyrel Datwyler /**
2524848c7085STyrel Datwyler  * ibmvfc_match_lun - Match function for specified LUN
2525848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2526848c7085STyrel Datwyler  * @device:	device to match (sdev)
2527848c7085STyrel Datwyler  *
2528848c7085STyrel Datwyler  * Returns:
2529848c7085STyrel Datwyler  *	1 if event matches sdev / 0 if event does not match sdev
2530848c7085STyrel Datwyler  **/
ibmvfc_match_lun(struct ibmvfc_event * evt,void * device)2531848c7085STyrel Datwyler static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device)
2532848c7085STyrel Datwyler {
2533848c7085STyrel Datwyler 	if (evt->cmnd && evt->cmnd->device == device)
2534848c7085STyrel Datwyler 		return 1;
2535848c7085STyrel Datwyler 	return 0;
2536848c7085STyrel Datwyler }
2537848c7085STyrel Datwyler 
2538848c7085STyrel Datwyler /**
2539848c7085STyrel Datwyler  * ibmvfc_event_is_free - Check if event is free or not
2540848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2541848c7085STyrel Datwyler  *
2542848c7085STyrel Datwyler  * Returns:
2543848c7085STyrel Datwyler  *	true / false
2544848c7085STyrel Datwyler  **/
ibmvfc_event_is_free(struct ibmvfc_event * evt)2545848c7085STyrel Datwyler static bool ibmvfc_event_is_free(struct ibmvfc_event *evt)
2546848c7085STyrel Datwyler {
2547848c7085STyrel Datwyler 	struct ibmvfc_event *loop_evt;
2548848c7085STyrel Datwyler 
2549848c7085STyrel Datwyler 	list_for_each_entry(loop_evt, &evt->queue->free, queue_list)
2550848c7085STyrel Datwyler 		if (loop_evt == evt)
2551848c7085STyrel Datwyler 			return true;
2552848c7085STyrel Datwyler 
2553848c7085STyrel Datwyler 	return false;
2554848c7085STyrel Datwyler }
2555848c7085STyrel Datwyler 
2556848c7085STyrel Datwyler /**
2557848c7085STyrel Datwyler  * ibmvfc_wait_for_ops - Wait for ops to complete
2558848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
2559848c7085STyrel Datwyler  * @device:	device to match (starget or sdev)
2560848c7085STyrel Datwyler  * @match:	match function
2561848c7085STyrel Datwyler  *
2562848c7085STyrel Datwyler  * Returns:
2563848c7085STyrel Datwyler  *	SUCCESS / FAILED
2564848c7085STyrel Datwyler  **/
ibmvfc_wait_for_ops(struct ibmvfc_host * vhost,void * device,int (* match)(struct ibmvfc_event *,void *))2565848c7085STyrel Datwyler static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
2566848c7085STyrel Datwyler 			       int (*match) (struct ibmvfc_event *, void *))
2567848c7085STyrel Datwyler {
2568848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
2569848c7085STyrel Datwyler 	DECLARE_COMPLETION_ONSTACK(comp);
2570848c7085STyrel Datwyler 	int wait, i, q_index, q_size;
2571848c7085STyrel Datwyler 	unsigned long flags;
2572848c7085STyrel Datwyler 	signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ;
2573848c7085STyrel Datwyler 	struct ibmvfc_queue *queues;
2574848c7085STyrel Datwyler 
2575848c7085STyrel Datwyler 	ENTER;
2576848c7085STyrel Datwyler 	if (vhost->mq_enabled && vhost->using_channels) {
2577848c7085STyrel Datwyler 		queues = vhost->scsi_scrqs.scrqs;
2578848c7085STyrel Datwyler 		q_size = vhost->scsi_scrqs.active_queues;
2579848c7085STyrel Datwyler 	} else {
2580848c7085STyrel Datwyler 		queues = &vhost->crq;
2581848c7085STyrel Datwyler 		q_size = 1;
2582848c7085STyrel Datwyler 	}
2583848c7085STyrel Datwyler 
2584848c7085STyrel Datwyler 	do {
2585848c7085STyrel Datwyler 		wait = 0;
2586848c7085STyrel Datwyler 		spin_lock_irqsave(vhost->host->host_lock, flags);
2587848c7085STyrel Datwyler 		for (q_index = 0; q_index < q_size; q_index++) {
2588848c7085STyrel Datwyler 			spin_lock(&queues[q_index].l_lock);
2589848c7085STyrel Datwyler 			for (i = 0; i < queues[q_index].evt_pool.size; i++) {
2590848c7085STyrel Datwyler 				evt = &queues[q_index].evt_pool.events[i];
2591848c7085STyrel Datwyler 				if (!ibmvfc_event_is_free(evt)) {
2592848c7085STyrel Datwyler 					if (match(evt, device)) {
2593848c7085STyrel Datwyler 						evt->eh_comp = &comp;
2594848c7085STyrel Datwyler 						wait++;
2595848c7085STyrel Datwyler 					}
2596848c7085STyrel Datwyler 				}
2597848c7085STyrel Datwyler 			}
2598848c7085STyrel Datwyler 			spin_unlock(&queues[q_index].l_lock);
2599848c7085STyrel Datwyler 		}
2600848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2601848c7085STyrel Datwyler 
2602848c7085STyrel Datwyler 		if (wait) {
2603848c7085STyrel Datwyler 			timeout = wait_for_completion_timeout(&comp, timeout);
2604848c7085STyrel Datwyler 
2605848c7085STyrel Datwyler 			if (!timeout) {
2606848c7085STyrel Datwyler 				wait = 0;
2607848c7085STyrel Datwyler 				spin_lock_irqsave(vhost->host->host_lock, flags);
2608848c7085STyrel Datwyler 				for (q_index = 0; q_index < q_size; q_index++) {
2609848c7085STyrel Datwyler 					spin_lock(&queues[q_index].l_lock);
2610848c7085STyrel Datwyler 					for (i = 0; i < queues[q_index].evt_pool.size; i++) {
2611848c7085STyrel Datwyler 						evt = &queues[q_index].evt_pool.events[i];
2612848c7085STyrel Datwyler 						if (!ibmvfc_event_is_free(evt)) {
2613848c7085STyrel Datwyler 							if (match(evt, device)) {
2614848c7085STyrel Datwyler 								evt->eh_comp = NULL;
2615848c7085STyrel Datwyler 								wait++;
2616848c7085STyrel Datwyler 							}
2617848c7085STyrel Datwyler 						}
2618848c7085STyrel Datwyler 					}
2619848c7085STyrel Datwyler 					spin_unlock(&queues[q_index].l_lock);
2620848c7085STyrel Datwyler 				}
2621848c7085STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
2622848c7085STyrel Datwyler 				if (wait)
2623848c7085STyrel Datwyler 					dev_err(vhost->dev, "Timed out waiting for aborted commands\n");
2624848c7085STyrel Datwyler 				LEAVE;
2625848c7085STyrel Datwyler 				return wait ? FAILED : SUCCESS;
2626848c7085STyrel Datwyler 			}
2627848c7085STyrel Datwyler 		}
2628848c7085STyrel Datwyler 	} while (wait);
2629848c7085STyrel Datwyler 
2630848c7085STyrel Datwyler 	LEAVE;
2631848c7085STyrel Datwyler 	return SUCCESS;
2632848c7085STyrel Datwyler }
2633848c7085STyrel Datwyler 
ibmvfc_init_tmf(struct ibmvfc_queue * queue,struct scsi_device * sdev,int type)2634848c7085STyrel Datwyler static struct ibmvfc_event *ibmvfc_init_tmf(struct ibmvfc_queue *queue,
2635848c7085STyrel Datwyler 					    struct scsi_device *sdev,
2636848c7085STyrel Datwyler 					    int type)
2637848c7085STyrel Datwyler {
2638848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
2639848c7085STyrel Datwyler 	struct scsi_target *starget = scsi_target(sdev);
2640848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(starget);
2641848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
2642848c7085STyrel Datwyler 	struct ibmvfc_tmf *tmf;
2643848c7085STyrel Datwyler 
2644848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(queue);
2645848c7085STyrel Datwyler 	if (!evt)
2646848c7085STyrel Datwyler 		return NULL;
2647848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
2648848c7085STyrel Datwyler 
2649848c7085STyrel Datwyler 	tmf = &evt->iu.tmf;
2650848c7085STyrel Datwyler 	memset(tmf, 0, sizeof(*tmf));
2651848c7085STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) {
2652848c7085STyrel Datwyler 		tmf->common.version = cpu_to_be32(2);
2653848c7085STyrel Datwyler 		tmf->target_wwpn = cpu_to_be64(rport->port_name);
2654848c7085STyrel Datwyler 	} else {
2655848c7085STyrel Datwyler 		tmf->common.version = cpu_to_be32(1);
2656848c7085STyrel Datwyler 	}
2657848c7085STyrel Datwyler 	tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD);
2658848c7085STyrel Datwyler 	tmf->common.length = cpu_to_be16(sizeof(*tmf));
2659848c7085STyrel Datwyler 	tmf->scsi_id = cpu_to_be64(rport->port_id);
2660848c7085STyrel Datwyler 	int_to_scsilun(sdev->lun, &tmf->lun);
2661848c7085STyrel Datwyler 	if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS))
2662848c7085STyrel Datwyler 		type &= ~IBMVFC_TMF_SUPPRESS_ABTS;
2663848c7085STyrel Datwyler 	if (vhost->state == IBMVFC_ACTIVE)
2664848c7085STyrel Datwyler 		tmf->flags = cpu_to_be32((type | IBMVFC_TMF_LUA_VALID));
2665848c7085STyrel Datwyler 	else
2666848c7085STyrel Datwyler 		tmf->flags = cpu_to_be32(((type & IBMVFC_TMF_SUPPRESS_ABTS) | IBMVFC_TMF_LUA_VALID));
2667848c7085STyrel Datwyler 	tmf->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata);
2668848c7085STyrel Datwyler 	tmf->my_cancel_key = cpu_to_be32((unsigned long)starget->hostdata);
2669848c7085STyrel Datwyler 
2670848c7085STyrel Datwyler 	init_completion(&evt->comp);
2671848c7085STyrel Datwyler 
2672848c7085STyrel Datwyler 	return evt;
2673848c7085STyrel Datwyler }
2674848c7085STyrel Datwyler 
ibmvfc_cancel_all_mq(struct scsi_device * sdev,int type)2675848c7085STyrel Datwyler static int ibmvfc_cancel_all_mq(struct scsi_device *sdev, int type)
2676848c7085STyrel Datwyler {
2677848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
2678848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *found_evt, *temp;
2679848c7085STyrel Datwyler 	struct ibmvfc_queue *queues = vhost->scsi_scrqs.scrqs;
2680848c7085STyrel Datwyler 	unsigned long flags;
2681848c7085STyrel Datwyler 	int num_hwq, i;
2682848c7085STyrel Datwyler 	int fail = 0;
2683848c7085STyrel Datwyler 	LIST_HEAD(cancelq);
2684848c7085STyrel Datwyler 	u16 status;
2685848c7085STyrel Datwyler 
2686848c7085STyrel Datwyler 	ENTER;
2687848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2688848c7085STyrel Datwyler 	num_hwq = vhost->scsi_scrqs.active_queues;
2689848c7085STyrel Datwyler 	for (i = 0; i < num_hwq; i++) {
2690848c7085STyrel Datwyler 		spin_lock(queues[i].q_lock);
2691848c7085STyrel Datwyler 		spin_lock(&queues[i].l_lock);
2692848c7085STyrel Datwyler 		found_evt = NULL;
2693848c7085STyrel Datwyler 		list_for_each_entry(evt, &queues[i].sent, queue_list) {
2694848c7085STyrel Datwyler 			if (evt->cmnd && evt->cmnd->device == sdev) {
2695848c7085STyrel Datwyler 				found_evt = evt;
2696848c7085STyrel Datwyler 				break;
2697848c7085STyrel Datwyler 			}
2698848c7085STyrel Datwyler 		}
2699848c7085STyrel Datwyler 		spin_unlock(&queues[i].l_lock);
2700848c7085STyrel Datwyler 
2701848c7085STyrel Datwyler 		if (found_evt && vhost->logged_in) {
2702848c7085STyrel Datwyler 			evt = ibmvfc_init_tmf(&queues[i], sdev, type);
2703848c7085STyrel Datwyler 			if (!evt) {
2704848c7085STyrel Datwyler 				spin_unlock(queues[i].q_lock);
2705848c7085STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
2706848c7085STyrel Datwyler 				return -ENOMEM;
2707848c7085STyrel Datwyler 			}
2708848c7085STyrel Datwyler 			evt->sync_iu = &queues[i].cancel_rsp;
2709848c7085STyrel Datwyler 			ibmvfc_send_event(evt, vhost, default_timeout);
2710848c7085STyrel Datwyler 			list_add_tail(&evt->cancel, &cancelq);
2711848c7085STyrel Datwyler 		}
2712848c7085STyrel Datwyler 
2713848c7085STyrel Datwyler 		spin_unlock(queues[i].q_lock);
2714848c7085STyrel Datwyler 	}
2715848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2716848c7085STyrel Datwyler 
2717848c7085STyrel Datwyler 	if (list_empty(&cancelq)) {
2718848c7085STyrel Datwyler 		if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL)
2719848c7085STyrel Datwyler 			sdev_printk(KERN_INFO, sdev, "No events found to cancel\n");
2720848c7085STyrel Datwyler 		return 0;
2721848c7085STyrel Datwyler 	}
2722848c7085STyrel Datwyler 
2723848c7085STyrel Datwyler 	sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n");
2724848c7085STyrel Datwyler 
2725848c7085STyrel Datwyler 	list_for_each_entry_safe(evt, temp, &cancelq, cancel) {
2726848c7085STyrel Datwyler 		wait_for_completion(&evt->comp);
2727848c7085STyrel Datwyler 		status = be16_to_cpu(evt->queue->cancel_rsp.mad_common.status);
2728848c7085STyrel Datwyler 		list_del(&evt->cancel);
2729848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
2730848c7085STyrel Datwyler 
2731848c7085STyrel Datwyler 		if (status != IBMVFC_MAD_SUCCESS) {
2732848c7085STyrel Datwyler 			sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status);
2733848c7085STyrel Datwyler 			switch (status) {
2734848c7085STyrel Datwyler 			case IBMVFC_MAD_DRIVER_FAILED:
2735848c7085STyrel Datwyler 			case IBMVFC_MAD_CRQ_ERROR:
2736848c7085STyrel Datwyler 			/* Host adapter most likely going through reset, return success to
2737848c7085STyrel Datwyler 			 * the caller will wait for the command being cancelled to get returned
2738848c7085STyrel Datwyler 			 */
2739848c7085STyrel Datwyler 				break;
2740848c7085STyrel Datwyler 			default:
2741848c7085STyrel Datwyler 				fail = 1;
2742848c7085STyrel Datwyler 				break;
2743848c7085STyrel Datwyler 			}
2744848c7085STyrel Datwyler 		}
2745848c7085STyrel Datwyler 	}
2746848c7085STyrel Datwyler 
2747848c7085STyrel Datwyler 	if (fail)
2748848c7085STyrel Datwyler 		return -EIO;
2749848c7085STyrel Datwyler 
2750848c7085STyrel Datwyler 	sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n");
2751848c7085STyrel Datwyler 	LEAVE;
2752848c7085STyrel Datwyler 	return 0;
2753848c7085STyrel Datwyler }
2754848c7085STyrel Datwyler 
ibmvfc_cancel_all_sq(struct scsi_device * sdev,int type)2755848c7085STyrel Datwyler static int ibmvfc_cancel_all_sq(struct scsi_device *sdev, int type)
2756848c7085STyrel Datwyler {
2757848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
2758848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *found_evt;
2759848c7085STyrel Datwyler 	union ibmvfc_iu rsp;
2760848c7085STyrel Datwyler 	int rsp_rc = -EBUSY;
2761848c7085STyrel Datwyler 	unsigned long flags;
2762848c7085STyrel Datwyler 	u16 status;
2763848c7085STyrel Datwyler 
2764848c7085STyrel Datwyler 	ENTER;
2765848c7085STyrel Datwyler 	found_evt = NULL;
2766848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2767848c7085STyrel Datwyler 	spin_lock(&vhost->crq.l_lock);
2768848c7085STyrel Datwyler 	list_for_each_entry(evt, &vhost->crq.sent, queue_list) {
2769848c7085STyrel Datwyler 		if (evt->cmnd && evt->cmnd->device == sdev) {
2770848c7085STyrel Datwyler 			found_evt = evt;
2771848c7085STyrel Datwyler 			break;
2772848c7085STyrel Datwyler 		}
2773848c7085STyrel Datwyler 	}
2774848c7085STyrel Datwyler 	spin_unlock(&vhost->crq.l_lock);
2775848c7085STyrel Datwyler 
2776848c7085STyrel Datwyler 	if (!found_evt) {
2777848c7085STyrel Datwyler 		if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL)
2778848c7085STyrel Datwyler 			sdev_printk(KERN_INFO, sdev, "No events found to cancel\n");
2779848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2780848c7085STyrel Datwyler 		return 0;
2781848c7085STyrel Datwyler 	}
2782848c7085STyrel Datwyler 
2783848c7085STyrel Datwyler 	if (vhost->logged_in) {
2784848c7085STyrel Datwyler 		evt = ibmvfc_init_tmf(&vhost->crq, sdev, type);
2785848c7085STyrel Datwyler 		evt->sync_iu = &rsp;
2786848c7085STyrel Datwyler 		rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout);
2787848c7085STyrel Datwyler 	}
2788848c7085STyrel Datwyler 
2789848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2790848c7085STyrel Datwyler 
2791848c7085STyrel Datwyler 	if (rsp_rc != 0) {
2792848c7085STyrel Datwyler 		sdev_printk(KERN_ERR, sdev, "Failed to send cancel event. rc=%d\n", rsp_rc);
2793848c7085STyrel Datwyler 		/* If failure is received, the host adapter is most likely going
2794848c7085STyrel Datwyler 		 through reset, return success so the caller will wait for the command
2795848c7085STyrel Datwyler 		 being cancelled to get returned */
2796848c7085STyrel Datwyler 		return 0;
2797848c7085STyrel Datwyler 	}
2798848c7085STyrel Datwyler 
2799848c7085STyrel Datwyler 	sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n");
2800848c7085STyrel Datwyler 
2801848c7085STyrel Datwyler 	wait_for_completion(&evt->comp);
2802848c7085STyrel Datwyler 	status = be16_to_cpu(rsp.mad_common.status);
2803848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2804848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2805848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2806848c7085STyrel Datwyler 
2807848c7085STyrel Datwyler 	if (status != IBMVFC_MAD_SUCCESS) {
2808848c7085STyrel Datwyler 		sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status);
2809848c7085STyrel Datwyler 		switch (status) {
2810848c7085STyrel Datwyler 		case IBMVFC_MAD_DRIVER_FAILED:
2811848c7085STyrel Datwyler 		case IBMVFC_MAD_CRQ_ERROR:
2812848c7085STyrel Datwyler 			/* Host adapter most likely going through reset, return success to
2813848c7085STyrel Datwyler 			 the caller will wait for the command being cancelled to get returned */
2814848c7085STyrel Datwyler 			return 0;
2815848c7085STyrel Datwyler 		default:
2816848c7085STyrel Datwyler 			return -EIO;
2817848c7085STyrel Datwyler 		};
2818848c7085STyrel Datwyler 	}
2819848c7085STyrel Datwyler 
2820848c7085STyrel Datwyler 	sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n");
2821848c7085STyrel Datwyler 	return 0;
2822848c7085STyrel Datwyler }
2823848c7085STyrel Datwyler 
2824848c7085STyrel Datwyler /**
2825848c7085STyrel Datwyler  * ibmvfc_cancel_all - Cancel all outstanding commands to the device
2826848c7085STyrel Datwyler  * @sdev:	scsi device to cancel commands
2827848c7085STyrel Datwyler  * @type:	type of error recovery being performed
2828848c7085STyrel Datwyler  *
2829848c7085STyrel Datwyler  * This sends a cancel to the VIOS for the specified device. This does
2830848c7085STyrel Datwyler  * NOT send any abort to the actual device. That must be done separately.
2831848c7085STyrel Datwyler  *
2832848c7085STyrel Datwyler  * Returns:
2833848c7085STyrel Datwyler  *	0 on success / other on failure
2834848c7085STyrel Datwyler  **/
ibmvfc_cancel_all(struct scsi_device * sdev,int type)2835848c7085STyrel Datwyler static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
2836848c7085STyrel Datwyler {
2837848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
2838848c7085STyrel Datwyler 
2839848c7085STyrel Datwyler 	if (vhost->mq_enabled && vhost->using_channels)
2840848c7085STyrel Datwyler 		return ibmvfc_cancel_all_mq(sdev, type);
2841848c7085STyrel Datwyler 	else
2842848c7085STyrel Datwyler 		return ibmvfc_cancel_all_sq(sdev, type);
2843848c7085STyrel Datwyler }
2844848c7085STyrel Datwyler 
2845848c7085STyrel Datwyler /**
2846848c7085STyrel Datwyler  * ibmvfc_match_key - Match function for specified cancel key
2847848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2848848c7085STyrel Datwyler  * @key:	cancel key to match
2849848c7085STyrel Datwyler  *
2850848c7085STyrel Datwyler  * Returns:
2851848c7085STyrel Datwyler  *	1 if event matches key / 0 if event does not match key
2852848c7085STyrel Datwyler  **/
ibmvfc_match_key(struct ibmvfc_event * evt,void * key)2853848c7085STyrel Datwyler static int ibmvfc_match_key(struct ibmvfc_event *evt, void *key)
2854848c7085STyrel Datwyler {
2855848c7085STyrel Datwyler 	unsigned long cancel_key = (unsigned long)key;
2856848c7085STyrel Datwyler 
2857848c7085STyrel Datwyler 	if (evt->crq.format == IBMVFC_CMD_FORMAT &&
2858848c7085STyrel Datwyler 	    be32_to_cpu(evt->iu.cmd.cancel_key) == cancel_key)
2859848c7085STyrel Datwyler 		return 1;
2860848c7085STyrel Datwyler 	return 0;
2861848c7085STyrel Datwyler }
2862848c7085STyrel Datwyler 
2863848c7085STyrel Datwyler /**
2864848c7085STyrel Datwyler  * ibmvfc_match_evt - Match function for specified event
2865848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
2866848c7085STyrel Datwyler  * @match:	event to match
2867848c7085STyrel Datwyler  *
2868848c7085STyrel Datwyler  * Returns:
2869848c7085STyrel Datwyler  *	1 if event matches key / 0 if event does not match key
2870848c7085STyrel Datwyler  **/
ibmvfc_match_evt(struct ibmvfc_event * evt,void * match)2871848c7085STyrel Datwyler static int ibmvfc_match_evt(struct ibmvfc_event *evt, void *match)
2872848c7085STyrel Datwyler {
2873848c7085STyrel Datwyler 	if (evt == match)
2874848c7085STyrel Datwyler 		return 1;
2875848c7085STyrel Datwyler 	return 0;
2876848c7085STyrel Datwyler }
2877848c7085STyrel Datwyler 
2878848c7085STyrel Datwyler /**
2879848c7085STyrel Datwyler  * ibmvfc_abort_task_set - Abort outstanding commands to the device
2880848c7085STyrel Datwyler  * @sdev:	scsi device to abort commands
2881848c7085STyrel Datwyler  *
2882848c7085STyrel Datwyler  * This sends an Abort Task Set to the VIOS for the specified device. This does
2883848c7085STyrel Datwyler  * NOT send any cancel to the VIOS. That must be done separately.
2884848c7085STyrel Datwyler  *
2885848c7085STyrel Datwyler  * Returns:
2886848c7085STyrel Datwyler  *	0 on success / other on failure
2887848c7085STyrel Datwyler  **/
ibmvfc_abort_task_set(struct scsi_device * sdev)2888848c7085STyrel Datwyler static int ibmvfc_abort_task_set(struct scsi_device *sdev)
2889848c7085STyrel Datwyler {
2890848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
2891848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
2892848c7085STyrel Datwyler 	struct ibmvfc_cmd *tmf;
2893848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *found_evt;
2894848c7085STyrel Datwyler 	union ibmvfc_iu rsp_iu;
2895848c7085STyrel Datwyler 	struct ibmvfc_fcp_cmd_iu *iu;
2896848c7085STyrel Datwyler 	struct ibmvfc_fcp_rsp *fc_rsp = ibmvfc_get_fcp_rsp(vhost, &rsp_iu.cmd);
2897848c7085STyrel Datwyler 	int rc, rsp_rc = -EBUSY;
2898848c7085STyrel Datwyler 	unsigned long flags, timeout = IBMVFC_ABORT_TIMEOUT;
2899848c7085STyrel Datwyler 	int rsp_code = 0;
2900848c7085STyrel Datwyler 
2901848c7085STyrel Datwyler 	found_evt = NULL;
2902848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2903848c7085STyrel Datwyler 	spin_lock(&vhost->crq.l_lock);
2904848c7085STyrel Datwyler 	list_for_each_entry(evt, &vhost->crq.sent, queue_list) {
2905848c7085STyrel Datwyler 		if (evt->cmnd && evt->cmnd->device == sdev) {
2906848c7085STyrel Datwyler 			found_evt = evt;
2907848c7085STyrel Datwyler 			break;
2908848c7085STyrel Datwyler 		}
2909848c7085STyrel Datwyler 	}
2910848c7085STyrel Datwyler 	spin_unlock(&vhost->crq.l_lock);
2911848c7085STyrel Datwyler 
2912848c7085STyrel Datwyler 	if (!found_evt) {
2913848c7085STyrel Datwyler 		if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL)
2914848c7085STyrel Datwyler 			sdev_printk(KERN_INFO, sdev, "No events found to abort\n");
2915848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
2916848c7085STyrel Datwyler 		return 0;
2917848c7085STyrel Datwyler 	}
2918848c7085STyrel Datwyler 
2919848c7085STyrel Datwyler 	if (vhost->state == IBMVFC_ACTIVE) {
2920848c7085STyrel Datwyler 		evt = ibmvfc_get_event(&vhost->crq);
2921848c7085STyrel Datwyler 		if (!evt) {
2922848c7085STyrel Datwyler 			spin_unlock_irqrestore(vhost->host->host_lock, flags);
2923848c7085STyrel Datwyler 			return -ENOMEM;
2924848c7085STyrel Datwyler 		}
2925848c7085STyrel Datwyler 		ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT);
2926848c7085STyrel Datwyler 		tmf = ibmvfc_init_vfc_cmd(evt, sdev);
2927848c7085STyrel Datwyler 		iu = ibmvfc_get_fcp_iu(vhost, tmf);
2928848c7085STyrel Datwyler 
2929848c7085STyrel Datwyler 		if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN))
2930848c7085STyrel Datwyler 			tmf->target_wwpn = cpu_to_be64(rport->port_name);
2931848c7085STyrel Datwyler 		iu->tmf_flags = IBMVFC_ABORT_TASK_SET;
2932848c7085STyrel Datwyler 		tmf->flags = cpu_to_be16((IBMVFC_NO_MEM_DESC | IBMVFC_TMF));
2933848c7085STyrel Datwyler 		evt->sync_iu = &rsp_iu;
2934848c7085STyrel Datwyler 
2935848c7085STyrel Datwyler 		tmf->correlation = cpu_to_be64((u64)evt);
2936848c7085STyrel Datwyler 
2937848c7085STyrel Datwyler 		init_completion(&evt->comp);
2938848c7085STyrel Datwyler 		rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout);
2939848c7085STyrel Datwyler 	}
2940848c7085STyrel Datwyler 
2941848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
2942848c7085STyrel Datwyler 
2943848c7085STyrel Datwyler 	if (rsp_rc != 0) {
2944848c7085STyrel Datwyler 		sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc);
2945848c7085STyrel Datwyler 		return -EIO;
2946848c7085STyrel Datwyler 	}
2947848c7085STyrel Datwyler 
2948848c7085STyrel Datwyler 	sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n");
2949848c7085STyrel Datwyler 	timeout = wait_for_completion_timeout(&evt->comp, timeout);
2950848c7085STyrel Datwyler 
2951848c7085STyrel Datwyler 	if (!timeout) {
2952848c7085STyrel Datwyler 		rc = ibmvfc_cancel_all(sdev, 0);
2953848c7085STyrel Datwyler 		if (!rc) {
2954848c7085STyrel Datwyler 			rc = ibmvfc_wait_for_ops(vhost, sdev->hostdata, ibmvfc_match_key);
2955848c7085STyrel Datwyler 			if (rc == SUCCESS)
2956848c7085STyrel Datwyler 				rc = 0;
2957848c7085STyrel Datwyler 		}
2958848c7085STyrel Datwyler 
2959848c7085STyrel Datwyler 		if (rc) {
2960848c7085STyrel Datwyler 			sdev_printk(KERN_INFO, sdev, "Cancel failed, resetting host\n");
2961848c7085STyrel Datwyler 			ibmvfc_reset_host(vhost);
2962848c7085STyrel Datwyler 			rsp_rc = -EIO;
2963848c7085STyrel Datwyler 			rc = ibmvfc_wait_for_ops(vhost, sdev->hostdata, ibmvfc_match_key);
2964848c7085STyrel Datwyler 
2965848c7085STyrel Datwyler 			if (rc == SUCCESS)
2966848c7085STyrel Datwyler 				rsp_rc = 0;
2967848c7085STyrel Datwyler 
2968848c7085STyrel Datwyler 			rc = ibmvfc_wait_for_ops(vhost, evt, ibmvfc_match_evt);
2969848c7085STyrel Datwyler 			if (rc != SUCCESS) {
2970848c7085STyrel Datwyler 				spin_lock_irqsave(vhost->host->host_lock, flags);
2971848c7085STyrel Datwyler 				ibmvfc_hard_reset_host(vhost);
2972848c7085STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
2973848c7085STyrel Datwyler 				rsp_rc = 0;
2974848c7085STyrel Datwyler 			}
2975848c7085STyrel Datwyler 
2976848c7085STyrel Datwyler 			goto out;
2977848c7085STyrel Datwyler 		}
2978848c7085STyrel Datwyler 	}
2979848c7085STyrel Datwyler 
2980848c7085STyrel Datwyler 	if (rsp_iu.cmd.status)
2981848c7085STyrel Datwyler 		rsp_code = ibmvfc_get_err_result(vhost, &rsp_iu.cmd);
2982848c7085STyrel Datwyler 
2983848c7085STyrel Datwyler 	if (rsp_code) {
2984848c7085STyrel Datwyler 		if (fc_rsp->flags & FCP_RSP_LEN_VALID)
2985848c7085STyrel Datwyler 			rsp_code = fc_rsp->data.info.rsp_code;
2986848c7085STyrel Datwyler 
2987848c7085STyrel Datwyler 		sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) "
2988848c7085STyrel Datwyler 			    "flags: %x fcp_rsp: %x, scsi_status: %x\n",
2989848c7085STyrel Datwyler 			    ibmvfc_get_cmd_error(be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error)),
2990848c7085STyrel Datwyler 			    be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error), fc_rsp->flags, rsp_code,
2991848c7085STyrel Datwyler 			    fc_rsp->scsi_status);
2992848c7085STyrel Datwyler 		rsp_rc = -EIO;
2993848c7085STyrel Datwyler 	} else
2994848c7085STyrel Datwyler 		sdev_printk(KERN_INFO, sdev, "Abort successful\n");
2995848c7085STyrel Datwyler 
2996848c7085STyrel Datwyler out:
2997848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
2998848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
2999848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
3000848c7085STyrel Datwyler 	return rsp_rc;
3001848c7085STyrel Datwyler }
3002848c7085STyrel Datwyler 
3003848c7085STyrel Datwyler /**
3004848c7085STyrel Datwyler  * ibmvfc_eh_abort_handler - Abort a command
3005848c7085STyrel Datwyler  * @cmd:	scsi command to abort
3006848c7085STyrel Datwyler  *
3007848c7085STyrel Datwyler  * Returns:
3008848c7085STyrel Datwyler  *	SUCCESS / FAST_IO_FAIL / FAILED
3009848c7085STyrel Datwyler  **/
ibmvfc_eh_abort_handler(struct scsi_cmnd * cmd)3010848c7085STyrel Datwyler static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd)
3011848c7085STyrel Datwyler {
3012848c7085STyrel Datwyler 	struct scsi_device *sdev = cmd->device;
3013848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
3014848c7085STyrel Datwyler 	int cancel_rc, block_rc;
3015848c7085STyrel Datwyler 	int rc = FAILED;
3016848c7085STyrel Datwyler 
3017848c7085STyrel Datwyler 	ENTER;
3018848c7085STyrel Datwyler 	block_rc = fc_block_scsi_eh(cmd);
3019848c7085STyrel Datwyler 	ibmvfc_wait_while_resetting(vhost);
3020848c7085STyrel Datwyler 	if (block_rc != FAST_IO_FAIL) {
3021848c7085STyrel Datwyler 		cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET);
3022848c7085STyrel Datwyler 		ibmvfc_abort_task_set(sdev);
3023848c7085STyrel Datwyler 	} else
3024848c7085STyrel Datwyler 		cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_SUPPRESS_ABTS);
3025848c7085STyrel Datwyler 
3026848c7085STyrel Datwyler 	if (!cancel_rc)
3027848c7085STyrel Datwyler 		rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun);
3028848c7085STyrel Datwyler 
3029848c7085STyrel Datwyler 	if (block_rc == FAST_IO_FAIL && rc != FAILED)
3030848c7085STyrel Datwyler 		rc = FAST_IO_FAIL;
3031848c7085STyrel Datwyler 
3032848c7085STyrel Datwyler 	LEAVE;
3033848c7085STyrel Datwyler 	return rc;
3034848c7085STyrel Datwyler }
3035848c7085STyrel Datwyler 
3036848c7085STyrel Datwyler /**
3037848c7085STyrel Datwyler  * ibmvfc_eh_device_reset_handler - Reset a single LUN
3038848c7085STyrel Datwyler  * @cmd:	scsi command struct
3039848c7085STyrel Datwyler  *
3040848c7085STyrel Datwyler  * Returns:
3041848c7085STyrel Datwyler  *	SUCCESS / FAST_IO_FAIL / FAILED
3042848c7085STyrel Datwyler  **/
ibmvfc_eh_device_reset_handler(struct scsi_cmnd * cmd)3043848c7085STyrel Datwyler static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd)
3044848c7085STyrel Datwyler {
3045848c7085STyrel Datwyler 	struct scsi_device *sdev = cmd->device;
3046848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(sdev->host);
3047848c7085STyrel Datwyler 	int cancel_rc, block_rc, reset_rc = 0;
3048848c7085STyrel Datwyler 	int rc = FAILED;
3049848c7085STyrel Datwyler 
3050848c7085STyrel Datwyler 	ENTER;
3051848c7085STyrel Datwyler 	block_rc = fc_block_scsi_eh(cmd);
3052848c7085STyrel Datwyler 	ibmvfc_wait_while_resetting(vhost);
3053848c7085STyrel Datwyler 	if (block_rc != FAST_IO_FAIL) {
3054848c7085STyrel Datwyler 		cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET);
3055848c7085STyrel Datwyler 		reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN");
3056848c7085STyrel Datwyler 	} else
3057848c7085STyrel Datwyler 		cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_SUPPRESS_ABTS);
3058848c7085STyrel Datwyler 
3059848c7085STyrel Datwyler 	if (!cancel_rc && !reset_rc)
3060848c7085STyrel Datwyler 		rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun);
3061848c7085STyrel Datwyler 
3062848c7085STyrel Datwyler 	if (block_rc == FAST_IO_FAIL && rc != FAILED)
3063848c7085STyrel Datwyler 		rc = FAST_IO_FAIL;
3064848c7085STyrel Datwyler 
3065848c7085STyrel Datwyler 	LEAVE;
3066848c7085STyrel Datwyler 	return rc;
3067848c7085STyrel Datwyler }
3068848c7085STyrel Datwyler 
3069848c7085STyrel Datwyler /**
3070848c7085STyrel Datwyler  * ibmvfc_dev_cancel_all_noreset - Device iterated cancel all function
3071848c7085STyrel Datwyler  * @sdev:	scsi device struct
3072848c7085STyrel Datwyler  * @data:	return code
3073848c7085STyrel Datwyler  *
3074848c7085STyrel Datwyler  **/
ibmvfc_dev_cancel_all_noreset(struct scsi_device * sdev,void * data)3075848c7085STyrel Datwyler static void ibmvfc_dev_cancel_all_noreset(struct scsi_device *sdev, void *data)
3076848c7085STyrel Datwyler {
3077848c7085STyrel Datwyler 	unsigned long *rc = data;
3078848c7085STyrel Datwyler 	*rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_SUPPRESS_ABTS);
3079848c7085STyrel Datwyler }
3080848c7085STyrel Datwyler 
3081848c7085STyrel Datwyler /**
3082848c7085STyrel Datwyler  * ibmvfc_eh_target_reset_handler - Reset the target
3083848c7085STyrel Datwyler  * @cmd:	scsi command struct
3084848c7085STyrel Datwyler  *
3085848c7085STyrel Datwyler  * Returns:
3086848c7085STyrel Datwyler  *	SUCCESS / FAST_IO_FAIL / FAILED
3087848c7085STyrel Datwyler  **/
ibmvfc_eh_target_reset_handler(struct scsi_cmnd * cmd)3088848c7085STyrel Datwyler static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd)
3089848c7085STyrel Datwyler {
3090848c7085STyrel Datwyler 	struct scsi_target *starget = scsi_target(cmd->device);
3091848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(starget);
3092848c7085STyrel Datwyler 	struct Scsi_Host *shost = rport_to_shost(rport);
3093848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3094848c7085STyrel Datwyler 	int block_rc;
3095848c7085STyrel Datwyler 	int reset_rc = 0;
3096848c7085STyrel Datwyler 	int rc = FAILED;
3097848c7085STyrel Datwyler 	unsigned long cancel_rc = 0;
3098848c7085STyrel Datwyler 	bool tgt_reset = false;
3099848c7085STyrel Datwyler 
3100848c7085STyrel Datwyler 	ENTER;
3101848c7085STyrel Datwyler 	block_rc = fc_block_rport(rport);
3102848c7085STyrel Datwyler 	ibmvfc_wait_while_resetting(vhost);
3103848c7085STyrel Datwyler 	if (block_rc != FAST_IO_FAIL) {
3104848c7085STyrel Datwyler 		struct scsi_device *sdev;
3105848c7085STyrel Datwyler 
3106848c7085STyrel Datwyler 		shost_for_each_device(sdev, shost) {
3107848c7085STyrel Datwyler 			if ((sdev->channel != starget->channel) ||
3108848c7085STyrel Datwyler 			    (sdev->id != starget->id))
3109848c7085STyrel Datwyler 				continue;
3110848c7085STyrel Datwyler 
3111848c7085STyrel Datwyler 			cancel_rc |= ibmvfc_cancel_all(sdev,
3112848c7085STyrel Datwyler 						       IBMVFC_TMF_TGT_RESET);
3113848c7085STyrel Datwyler 			if (!tgt_reset) {
3114848c7085STyrel Datwyler 				reset_rc = ibmvfc_reset_device(sdev,
3115848c7085STyrel Datwyler 					IBMVFC_TARGET_RESET, "target");
3116848c7085STyrel Datwyler 				tgt_reset = true;
3117848c7085STyrel Datwyler 			}
3118848c7085STyrel Datwyler 		}
3119848c7085STyrel Datwyler 	} else
3120848c7085STyrel Datwyler 		starget_for_each_device(starget, &cancel_rc,
3121848c7085STyrel Datwyler 					ibmvfc_dev_cancel_all_noreset);
3122848c7085STyrel Datwyler 
3123848c7085STyrel Datwyler 	if (!cancel_rc && !reset_rc)
3124848c7085STyrel Datwyler 		rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target);
3125848c7085STyrel Datwyler 
3126848c7085STyrel Datwyler 	if (block_rc == FAST_IO_FAIL && rc != FAILED)
3127848c7085STyrel Datwyler 		rc = FAST_IO_FAIL;
3128848c7085STyrel Datwyler 
3129848c7085STyrel Datwyler 	LEAVE;
3130848c7085STyrel Datwyler 	return rc;
3131848c7085STyrel Datwyler }
3132848c7085STyrel Datwyler 
3133848c7085STyrel Datwyler /**
3134848c7085STyrel Datwyler  * ibmvfc_eh_host_reset_handler - Reset the connection to the server
3135848c7085STyrel Datwyler  * @cmd:	struct scsi_cmnd having problems
3136848c7085STyrel Datwyler  *
3137848c7085STyrel Datwyler  **/
ibmvfc_eh_host_reset_handler(struct scsi_cmnd * cmd)3138848c7085STyrel Datwyler static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd)
3139848c7085STyrel Datwyler {
3140848c7085STyrel Datwyler 	int rc;
3141848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
3142848c7085STyrel Datwyler 
3143848c7085STyrel Datwyler 	dev_err(vhost->dev, "Resetting connection due to error recovery\n");
3144848c7085STyrel Datwyler 	rc = ibmvfc_issue_fc_host_lip(vhost->host);
3145848c7085STyrel Datwyler 
3146848c7085STyrel Datwyler 	return rc ? FAILED : SUCCESS;
3147848c7085STyrel Datwyler }
3148848c7085STyrel Datwyler 
3149848c7085STyrel Datwyler /**
3150848c7085STyrel Datwyler  * ibmvfc_terminate_rport_io - Terminate all pending I/O to the rport.
3151848c7085STyrel Datwyler  * @rport:		rport struct
3152848c7085STyrel Datwyler  *
3153848c7085STyrel Datwyler  * Return value:
3154848c7085STyrel Datwyler  * 	none
3155848c7085STyrel Datwyler  **/
ibmvfc_terminate_rport_io(struct fc_rport * rport)3156848c7085STyrel Datwyler static void ibmvfc_terminate_rport_io(struct fc_rport *rport)
3157848c7085STyrel Datwyler {
3158848c7085STyrel Datwyler 	struct Scsi_Host *shost = rport_to_shost(rport);
3159848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3160848c7085STyrel Datwyler 	struct fc_rport *dev_rport;
3161848c7085STyrel Datwyler 	struct scsi_device *sdev;
3162848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
3163848c7085STyrel Datwyler 	unsigned long rc, flags;
3164848c7085STyrel Datwyler 	unsigned int found;
3165848c7085STyrel Datwyler 
3166848c7085STyrel Datwyler 	ENTER;
3167848c7085STyrel Datwyler 	shost_for_each_device(sdev, shost) {
3168848c7085STyrel Datwyler 		dev_rport = starget_to_rport(scsi_target(sdev));
3169848c7085STyrel Datwyler 		if (dev_rport != rport)
3170848c7085STyrel Datwyler 			continue;
3171848c7085STyrel Datwyler 		ibmvfc_cancel_all(sdev, IBMVFC_TMF_SUPPRESS_ABTS);
3172848c7085STyrel Datwyler 	}
3173848c7085STyrel Datwyler 
3174848c7085STyrel Datwyler 	rc = ibmvfc_wait_for_ops(vhost, rport, ibmvfc_match_rport);
3175848c7085STyrel Datwyler 
3176848c7085STyrel Datwyler 	if (rc == FAILED)
3177848c7085STyrel Datwyler 		ibmvfc_issue_fc_host_lip(shost);
3178848c7085STyrel Datwyler 
3179848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3180848c7085STyrel Datwyler 	found = 0;
3181848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
3182848c7085STyrel Datwyler 		if (tgt->scsi_id == rport->port_id) {
3183848c7085STyrel Datwyler 			found++;
3184848c7085STyrel Datwyler 			break;
3185848c7085STyrel Datwyler 		}
3186848c7085STyrel Datwyler 	}
3187848c7085STyrel Datwyler 
3188848c7085STyrel Datwyler 	if (found && tgt->action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) {
3189848c7085STyrel Datwyler 		/*
3190848c7085STyrel Datwyler 		 * If we get here, that means we previously attempted to send
3191848c7085STyrel Datwyler 		 * an implicit logout to the target but it failed, most likely
3192848c7085STyrel Datwyler 		 * due to I/O being pending, so we need to send it again
3193848c7085STyrel Datwyler 		 */
3194848c7085STyrel Datwyler 		ibmvfc_del_tgt(tgt);
3195848c7085STyrel Datwyler 		ibmvfc_reinit_host(vhost);
3196848c7085STyrel Datwyler 	}
3197848c7085STyrel Datwyler 
3198848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3199848c7085STyrel Datwyler 	LEAVE;
3200848c7085STyrel Datwyler }
3201848c7085STyrel Datwyler 
3202848c7085STyrel Datwyler static const struct ibmvfc_async_desc ae_desc [] = {
3203848c7085STyrel Datwyler 	{ "PLOGI",	IBMVFC_AE_ELS_PLOGI,	IBMVFC_DEFAULT_LOG_LEVEL + 1 },
3204848c7085STyrel Datwyler 	{ "LOGO",	IBMVFC_AE_ELS_LOGO,	IBMVFC_DEFAULT_LOG_LEVEL + 1 },
3205848c7085STyrel Datwyler 	{ "PRLO",	IBMVFC_AE_ELS_PRLO,	IBMVFC_DEFAULT_LOG_LEVEL + 1 },
3206848c7085STyrel Datwyler 	{ "N-Port SCN",	IBMVFC_AE_SCN_NPORT,	IBMVFC_DEFAULT_LOG_LEVEL + 1 },
3207848c7085STyrel Datwyler 	{ "Group SCN",	IBMVFC_AE_SCN_GROUP,	IBMVFC_DEFAULT_LOG_LEVEL + 1 },
3208848c7085STyrel Datwyler 	{ "Domain SCN",	IBMVFC_AE_SCN_DOMAIN,	IBMVFC_DEFAULT_LOG_LEVEL },
3209848c7085STyrel Datwyler 	{ "Fabric SCN",	IBMVFC_AE_SCN_FABRIC,	IBMVFC_DEFAULT_LOG_LEVEL },
3210848c7085STyrel Datwyler 	{ "Link Up",	IBMVFC_AE_LINK_UP,	IBMVFC_DEFAULT_LOG_LEVEL },
3211848c7085STyrel Datwyler 	{ "Link Down",	IBMVFC_AE_LINK_DOWN,	IBMVFC_DEFAULT_LOG_LEVEL },
3212848c7085STyrel Datwyler 	{ "Link Dead",	IBMVFC_AE_LINK_DEAD,	IBMVFC_DEFAULT_LOG_LEVEL },
3213848c7085STyrel Datwyler 	{ "Halt",	IBMVFC_AE_HALT,		IBMVFC_DEFAULT_LOG_LEVEL },
3214848c7085STyrel Datwyler 	{ "Resume",	IBMVFC_AE_RESUME,	IBMVFC_DEFAULT_LOG_LEVEL },
3215848c7085STyrel Datwyler 	{ "Adapter Failed", IBMVFC_AE_ADAPTER_FAILED, IBMVFC_DEFAULT_LOG_LEVEL },
3216848c7085STyrel Datwyler };
3217848c7085STyrel Datwyler 
3218848c7085STyrel Datwyler static const struct ibmvfc_async_desc unknown_ae = {
3219848c7085STyrel Datwyler 	"Unknown async", 0, IBMVFC_DEFAULT_LOG_LEVEL
3220848c7085STyrel Datwyler };
3221848c7085STyrel Datwyler 
3222848c7085STyrel Datwyler /**
3223848c7085STyrel Datwyler  * ibmvfc_get_ae_desc - Get text description for async event
3224848c7085STyrel Datwyler  * @ae:	async event
3225848c7085STyrel Datwyler  *
3226848c7085STyrel Datwyler  **/
ibmvfc_get_ae_desc(u64 ae)3227848c7085STyrel Datwyler static const struct ibmvfc_async_desc *ibmvfc_get_ae_desc(u64 ae)
3228848c7085STyrel Datwyler {
3229848c7085STyrel Datwyler 	int i;
3230848c7085STyrel Datwyler 
3231848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(ae_desc); i++)
3232848c7085STyrel Datwyler 		if (ae_desc[i].ae == ae)
3233848c7085STyrel Datwyler 			return &ae_desc[i];
3234848c7085STyrel Datwyler 
3235848c7085STyrel Datwyler 	return &unknown_ae;
3236848c7085STyrel Datwyler }
3237848c7085STyrel Datwyler 
3238848c7085STyrel Datwyler static const struct {
3239848c7085STyrel Datwyler 	enum ibmvfc_ae_link_state state;
3240848c7085STyrel Datwyler 	const char *desc;
3241848c7085STyrel Datwyler } link_desc [] = {
3242848c7085STyrel Datwyler 	{ IBMVFC_AE_LS_LINK_UP,		" link up" },
3243848c7085STyrel Datwyler 	{ IBMVFC_AE_LS_LINK_BOUNCED,	" link bounced" },
3244848c7085STyrel Datwyler 	{ IBMVFC_AE_LS_LINK_DOWN,	" link down" },
3245848c7085STyrel Datwyler 	{ IBMVFC_AE_LS_LINK_DEAD,	" link dead" },
3246848c7085STyrel Datwyler };
3247848c7085STyrel Datwyler 
3248848c7085STyrel Datwyler /**
3249848c7085STyrel Datwyler  * ibmvfc_get_link_state - Get text description for link state
3250848c7085STyrel Datwyler  * @state:	link state
3251848c7085STyrel Datwyler  *
3252848c7085STyrel Datwyler  **/
ibmvfc_get_link_state(enum ibmvfc_ae_link_state state)3253848c7085STyrel Datwyler static const char *ibmvfc_get_link_state(enum ibmvfc_ae_link_state state)
3254848c7085STyrel Datwyler {
3255848c7085STyrel Datwyler 	int i;
3256848c7085STyrel Datwyler 
3257848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(link_desc); i++)
3258848c7085STyrel Datwyler 		if (link_desc[i].state == state)
3259848c7085STyrel Datwyler 			return link_desc[i].desc;
3260848c7085STyrel Datwyler 
3261848c7085STyrel Datwyler 	return "";
3262848c7085STyrel Datwyler }
3263848c7085STyrel Datwyler 
3264848c7085STyrel Datwyler /**
3265848c7085STyrel Datwyler  * ibmvfc_handle_async - Handle an async event from the adapter
3266848c7085STyrel Datwyler  * @crq:	crq to process
3267848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
3268848c7085STyrel Datwyler  *
3269848c7085STyrel Datwyler  **/
ibmvfc_handle_async(struct ibmvfc_async_crq * crq,struct ibmvfc_host * vhost)3270848c7085STyrel Datwyler static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
3271848c7085STyrel Datwyler 				struct ibmvfc_host *vhost)
3272848c7085STyrel Datwyler {
3273848c7085STyrel Datwyler 	const struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(be64_to_cpu(crq->event));
3274848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
3275848c7085STyrel Datwyler 
3276848c7085STyrel Datwyler 	ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwpn: %llx,"
3277848c7085STyrel Datwyler 		   " node_name: %llx%s\n", desc->desc, be64_to_cpu(crq->scsi_id),
3278848c7085STyrel Datwyler 		   be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name),
3279848c7085STyrel Datwyler 		   ibmvfc_get_link_state(crq->link_state));
3280848c7085STyrel Datwyler 
3281848c7085STyrel Datwyler 	switch (be64_to_cpu(crq->event)) {
3282848c7085STyrel Datwyler 	case IBMVFC_AE_RESUME:
3283848c7085STyrel Datwyler 		switch (crq->link_state) {
3284848c7085STyrel Datwyler 		case IBMVFC_AE_LS_LINK_DOWN:
3285848c7085STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
3286848c7085STyrel Datwyler 			break;
3287848c7085STyrel Datwyler 		case IBMVFC_AE_LS_LINK_DEAD:
3288848c7085STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
3289848c7085STyrel Datwyler 			break;
3290848c7085STyrel Datwyler 		case IBMVFC_AE_LS_LINK_UP:
3291848c7085STyrel Datwyler 		case IBMVFC_AE_LS_LINK_BOUNCED:
3292848c7085STyrel Datwyler 		default:
3293848c7085STyrel Datwyler 			vhost->events_to_log |= IBMVFC_AE_LINKUP;
3294848c7085STyrel Datwyler 			vhost->delay_init = 1;
3295848c7085STyrel Datwyler 			__ibmvfc_reset_host(vhost);
3296848c7085STyrel Datwyler 			break;
3297848c7085STyrel Datwyler 		}
3298848c7085STyrel Datwyler 
3299848c7085STyrel Datwyler 		break;
3300848c7085STyrel Datwyler 	case IBMVFC_AE_LINK_UP:
3301848c7085STyrel Datwyler 		vhost->events_to_log |= IBMVFC_AE_LINKUP;
3302848c7085STyrel Datwyler 		vhost->delay_init = 1;
3303848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
3304848c7085STyrel Datwyler 		break;
3305848c7085STyrel Datwyler 	case IBMVFC_AE_SCN_FABRIC:
3306848c7085STyrel Datwyler 	case IBMVFC_AE_SCN_DOMAIN:
3307848c7085STyrel Datwyler 		vhost->events_to_log |= IBMVFC_AE_RSCN;
3308848c7085STyrel Datwyler 		if (vhost->state < IBMVFC_HALTED) {
3309848c7085STyrel Datwyler 			vhost->delay_init = 1;
3310848c7085STyrel Datwyler 			__ibmvfc_reset_host(vhost);
3311848c7085STyrel Datwyler 		}
3312848c7085STyrel Datwyler 		break;
3313848c7085STyrel Datwyler 	case IBMVFC_AE_SCN_NPORT:
3314848c7085STyrel Datwyler 	case IBMVFC_AE_SCN_GROUP:
3315848c7085STyrel Datwyler 		vhost->events_to_log |= IBMVFC_AE_RSCN;
3316848c7085STyrel Datwyler 		ibmvfc_reinit_host(vhost);
3317848c7085STyrel Datwyler 		break;
3318848c7085STyrel Datwyler 	case IBMVFC_AE_ELS_LOGO:
3319848c7085STyrel Datwyler 	case IBMVFC_AE_ELS_PRLO:
3320848c7085STyrel Datwyler 	case IBMVFC_AE_ELS_PLOGI:
3321848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
3322848c7085STyrel Datwyler 			if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
3323848c7085STyrel Datwyler 				break;
3324848c7085STyrel Datwyler 			if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id)
3325848c7085STyrel Datwyler 				continue;
3326848c7085STyrel Datwyler 			if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn)
3327848c7085STyrel Datwyler 				continue;
3328848c7085STyrel Datwyler 			if (crq->node_name && cpu_to_be64(tgt->ids.node_name) != crq->node_name)
3329848c7085STyrel Datwyler 				continue;
3330848c7085STyrel Datwyler 			if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO)
3331848c7085STyrel Datwyler 				tgt->logo_rcvd = 1;
3332848c7085STyrel Datwyler 			if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) {
3333848c7085STyrel Datwyler 				ibmvfc_del_tgt(tgt);
3334848c7085STyrel Datwyler 				ibmvfc_reinit_host(vhost);
3335848c7085STyrel Datwyler 			}
3336848c7085STyrel Datwyler 		}
3337e0fca728STyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
3338e0fca728STyrel Datwyler 			if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
3339e0fca728STyrel Datwyler 				break;
3340e0fca728STyrel Datwyler 			if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id)
3341e0fca728STyrel Datwyler 				continue;
3342e0fca728STyrel Datwyler 			if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn)
3343e0fca728STyrel Datwyler 				continue;
3344e0fca728STyrel Datwyler 			if (crq->node_name && cpu_to_be64(tgt->ids.node_name) != crq->node_name)
3345e0fca728STyrel Datwyler 				continue;
3346e0fca728STyrel Datwyler 			if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO)
3347e0fca728STyrel Datwyler 				tgt->logo_rcvd = 1;
3348e0fca728STyrel Datwyler 			if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) {
3349e0fca728STyrel Datwyler 				ibmvfc_del_tgt(tgt);
3350e0fca728STyrel Datwyler 				ibmvfc_reinit_host(vhost);
3351e0fca728STyrel Datwyler 			}
3352e0fca728STyrel Datwyler 		}
3353848c7085STyrel Datwyler 		break;
3354848c7085STyrel Datwyler 	case IBMVFC_AE_LINK_DOWN:
3355848c7085STyrel Datwyler 	case IBMVFC_AE_ADAPTER_FAILED:
3356848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
3357848c7085STyrel Datwyler 		break;
3358848c7085STyrel Datwyler 	case IBMVFC_AE_LINK_DEAD:
3359848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
3360848c7085STyrel Datwyler 		break;
3361848c7085STyrel Datwyler 	case IBMVFC_AE_HALT:
3362848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_HALTED);
3363848c7085STyrel Datwyler 		break;
3364848c7085STyrel Datwyler 	default:
3365848c7085STyrel Datwyler 		dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event);
3366848c7085STyrel Datwyler 		break;
3367848c7085STyrel Datwyler 	}
3368848c7085STyrel Datwyler }
3369848c7085STyrel Datwyler 
3370848c7085STyrel Datwyler /**
3371848c7085STyrel Datwyler  * ibmvfc_handle_crq - Handles and frees received events in the CRQ
3372848c7085STyrel Datwyler  * @crq:	Command/Response queue
3373848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
3374848c7085STyrel Datwyler  * @evt_doneq:	Event done queue
3375848c7085STyrel Datwyler  *
3376848c7085STyrel Datwyler **/
ibmvfc_handle_crq(struct ibmvfc_crq * crq,struct ibmvfc_host * vhost,struct list_head * evt_doneq)3377848c7085STyrel Datwyler static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost,
3378848c7085STyrel Datwyler 			      struct list_head *evt_doneq)
3379848c7085STyrel Datwyler {
3380848c7085STyrel Datwyler 	long rc;
3381848c7085STyrel Datwyler 	struct ibmvfc_event *evt = (struct ibmvfc_event *)be64_to_cpu(crq->ioba);
3382848c7085STyrel Datwyler 
3383848c7085STyrel Datwyler 	switch (crq->valid) {
3384848c7085STyrel Datwyler 	case IBMVFC_CRQ_INIT_RSP:
3385848c7085STyrel Datwyler 		switch (crq->format) {
3386848c7085STyrel Datwyler 		case IBMVFC_CRQ_INIT:
3387848c7085STyrel Datwyler 			dev_info(vhost->dev, "Partner initialized\n");
3388848c7085STyrel Datwyler 			/* Send back a response */
3389848c7085STyrel Datwyler 			rc = ibmvfc_send_crq_init_complete(vhost);
3390848c7085STyrel Datwyler 			if (rc == 0)
3391848c7085STyrel Datwyler 				ibmvfc_init_host(vhost);
3392848c7085STyrel Datwyler 			else
3393848c7085STyrel Datwyler 				dev_err(vhost->dev, "Unable to send init rsp. rc=%ld\n", rc);
3394848c7085STyrel Datwyler 			break;
3395848c7085STyrel Datwyler 		case IBMVFC_CRQ_INIT_COMPLETE:
3396848c7085STyrel Datwyler 			dev_info(vhost->dev, "Partner initialization complete\n");
3397848c7085STyrel Datwyler 			ibmvfc_init_host(vhost);
3398848c7085STyrel Datwyler 			break;
3399848c7085STyrel Datwyler 		default:
3400848c7085STyrel Datwyler 			dev_err(vhost->dev, "Unknown crq message type: %d\n", crq->format);
3401848c7085STyrel Datwyler 		}
3402848c7085STyrel Datwyler 		return;
3403848c7085STyrel Datwyler 	case IBMVFC_CRQ_XPORT_EVENT:
3404848c7085STyrel Datwyler 		vhost->state = IBMVFC_NO_CRQ;
3405848c7085STyrel Datwyler 		vhost->logged_in = 0;
3406848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
3407848c7085STyrel Datwyler 		if (crq->format == IBMVFC_PARTITION_MIGRATED) {
3408848c7085STyrel Datwyler 			/* We need to re-setup the interpartition connection */
3409848c7085STyrel Datwyler 			dev_info(vhost->dev, "Partition migrated, Re-enabling adapter\n");
3410848c7085STyrel Datwyler 			vhost->client_migrated = 1;
3411848c7085STyrel Datwyler 
3412848c7085STyrel Datwyler 			scsi_block_requests(vhost->host);
3413848c7085STyrel Datwyler 			ibmvfc_purge_requests(vhost, DID_REQUEUE);
3414848c7085STyrel Datwyler 			ibmvfc_set_host_state(vhost, IBMVFC_LINK_DOWN);
3415848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
3416848c7085STyrel Datwyler 			wake_up(&vhost->work_wait_q);
3417848c7085STyrel Datwyler 		} else if (crq->format == IBMVFC_PARTNER_FAILED || crq->format == IBMVFC_PARTNER_DEREGISTER) {
3418848c7085STyrel Datwyler 			dev_err(vhost->dev, "Host partner adapter deregistered or failed (rc=%d)\n", crq->format);
3419848c7085STyrel Datwyler 			ibmvfc_purge_requests(vhost, DID_ERROR);
3420848c7085STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
3421848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
3422848c7085STyrel Datwyler 		} else {
3423848c7085STyrel Datwyler 			dev_err(vhost->dev, "Received unknown transport event from partner (rc=%d)\n", crq->format);
3424848c7085STyrel Datwyler 		}
3425848c7085STyrel Datwyler 		return;
3426848c7085STyrel Datwyler 	case IBMVFC_CRQ_CMD_RSP:
3427848c7085STyrel Datwyler 		break;
3428848c7085STyrel Datwyler 	default:
3429848c7085STyrel Datwyler 		dev_err(vhost->dev, "Got an invalid message type 0x%02x\n", crq->valid);
3430848c7085STyrel Datwyler 		return;
3431848c7085STyrel Datwyler 	}
3432848c7085STyrel Datwyler 
3433848c7085STyrel Datwyler 	if (crq->format == IBMVFC_ASYNC_EVENT)
3434848c7085STyrel Datwyler 		return;
3435848c7085STyrel Datwyler 
3436848c7085STyrel Datwyler 	/* The only kind of payload CRQs we should get are responses to
3437848c7085STyrel Datwyler 	 * things we send. Make sure this response is to something we
3438848c7085STyrel Datwyler 	 * actually sent
3439848c7085STyrel Datwyler 	 */
3440848c7085STyrel Datwyler 	if (unlikely(!ibmvfc_valid_event(&vhost->crq.evt_pool, evt))) {
3441848c7085STyrel Datwyler 		dev_err(vhost->dev, "Returned correlation_token 0x%08llx is invalid!\n",
3442848c7085STyrel Datwyler 			crq->ioba);
3443848c7085STyrel Datwyler 		return;
3444848c7085STyrel Datwyler 	}
3445848c7085STyrel Datwyler 
3446848c7085STyrel Datwyler 	if (unlikely(atomic_dec_if_positive(&evt->active))) {
3447848c7085STyrel Datwyler 		dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n",
3448848c7085STyrel Datwyler 			crq->ioba);
3449848c7085STyrel Datwyler 		return;
3450848c7085STyrel Datwyler 	}
3451848c7085STyrel Datwyler 
3452848c7085STyrel Datwyler 	spin_lock(&evt->queue->l_lock);
3453848c7085STyrel Datwyler 	list_move_tail(&evt->queue_list, evt_doneq);
3454848c7085STyrel Datwyler 	spin_unlock(&evt->queue->l_lock);
3455848c7085STyrel Datwyler }
3456848c7085STyrel Datwyler 
3457848c7085STyrel Datwyler /**
3458848c7085STyrel Datwyler  * ibmvfc_scan_finished - Check if the device scan is done.
3459848c7085STyrel Datwyler  * @shost:	scsi host struct
3460848c7085STyrel Datwyler  * @time:	current elapsed time
3461848c7085STyrel Datwyler  *
3462848c7085STyrel Datwyler  * Returns:
3463848c7085STyrel Datwyler  *	0 if scan is not done / 1 if scan is done
3464848c7085STyrel Datwyler  **/
ibmvfc_scan_finished(struct Scsi_Host * shost,unsigned long time)3465848c7085STyrel Datwyler static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
3466848c7085STyrel Datwyler {
3467848c7085STyrel Datwyler 	unsigned long flags;
3468848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3469848c7085STyrel Datwyler 	int done = 0;
3470848c7085STyrel Datwyler 
3471848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3472848c7085STyrel Datwyler 	if (!vhost->scan_timeout)
3473848c7085STyrel Datwyler 		done = 1;
3474848c7085STyrel Datwyler 	else if (time >= (vhost->scan_timeout * HZ)) {
3475848c7085STyrel Datwyler 		dev_info(vhost->dev, "Scan taking longer than %d seconds, "
3476848c7085STyrel Datwyler 			 "continuing initialization\n", vhost->scan_timeout);
3477848c7085STyrel Datwyler 		done = 1;
3478848c7085STyrel Datwyler 	}
3479848c7085STyrel Datwyler 
3480848c7085STyrel Datwyler 	if (vhost->scan_complete) {
3481848c7085STyrel Datwyler 		vhost->scan_timeout = init_timeout;
3482848c7085STyrel Datwyler 		done = 1;
3483848c7085STyrel Datwyler 	}
3484848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3485848c7085STyrel Datwyler 	return done;
3486848c7085STyrel Datwyler }
3487848c7085STyrel Datwyler 
3488848c7085STyrel Datwyler /**
3489848c7085STyrel Datwyler  * ibmvfc_sdev_init - Setup the device's task set value
3490848c7085STyrel Datwyler  * @sdev:	struct scsi_device device to configure
3491848c7085STyrel Datwyler  *
3492848c7085STyrel Datwyler  * Set the device's task set value so that error handling works as
3493848c7085STyrel Datwyler  * expected.
3494848c7085STyrel Datwyler  *
3495848c7085STyrel Datwyler  * Returns:
3496848c7085STyrel Datwyler  *	0 on success / -ENXIO if device does not exist
3497848c7085STyrel Datwyler  **/
ibmvfc_sdev_init(struct scsi_device * sdev)3498848c7085STyrel Datwyler static int ibmvfc_sdev_init(struct scsi_device *sdev)
3499848c7085STyrel Datwyler {
3500848c7085STyrel Datwyler 	struct Scsi_Host *shost = sdev->host;
3501848c7085STyrel Datwyler 	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
3502848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3503848c7085STyrel Datwyler 	unsigned long flags = 0;
3504848c7085STyrel Datwyler 
3505848c7085STyrel Datwyler 	if (!rport || fc_remote_port_chkready(rport))
3506848c7085STyrel Datwyler 		return -ENXIO;
3507848c7085STyrel Datwyler 
3508848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3509848c7085STyrel Datwyler 	sdev->hostdata = (void *)(unsigned long)vhost->task_set++;
3510848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3511848c7085STyrel Datwyler 	return 0;
3512848c7085STyrel Datwyler }
3513848c7085STyrel Datwyler 
3514848c7085STyrel Datwyler /**
3515848c7085STyrel Datwyler  * ibmvfc_target_alloc - Setup the target's task set value
3516848c7085STyrel Datwyler  * @starget:	struct scsi_target
3517848c7085STyrel Datwyler  *
3518848c7085STyrel Datwyler  * Set the target's task set value so that error handling works as
3519848c7085STyrel Datwyler  * expected.
3520848c7085STyrel Datwyler  *
3521848c7085STyrel Datwyler  * Returns:
3522848c7085STyrel Datwyler  *	0 on success / -ENXIO if device does not exist
3523848c7085STyrel Datwyler  **/
ibmvfc_target_alloc(struct scsi_target * starget)3524848c7085STyrel Datwyler static int ibmvfc_target_alloc(struct scsi_target *starget)
3525848c7085STyrel Datwyler {
3526848c7085STyrel Datwyler 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
3527848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3528848c7085STyrel Datwyler 	unsigned long flags = 0;
3529848c7085STyrel Datwyler 
3530848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3531848c7085STyrel Datwyler 	starget->hostdata = (void *)(unsigned long)vhost->task_set++;
3532848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3533848c7085STyrel Datwyler 	return 0;
3534848c7085STyrel Datwyler }
3535848c7085STyrel Datwyler 
3536848c7085STyrel Datwyler /**
3537848c7085STyrel Datwyler  * ibmvfc_sdev_configure - Configure the device
3538848c7085STyrel Datwyler  * @sdev:	struct scsi_device device to configure
3539848c7085STyrel Datwyler  * @lim:	Request queue limits
3540848c7085STyrel Datwyler  *
3541848c7085STyrel Datwyler  * Enable allow_restart for a device if it is a disk. Adjust the
3542848c7085STyrel Datwyler  * queue_depth here also.
3543848c7085STyrel Datwyler  *
3544848c7085STyrel Datwyler  * Returns:
3545848c7085STyrel Datwyler  *	0
3546848c7085STyrel Datwyler  **/
ibmvfc_sdev_configure(struct scsi_device * sdev,struct queue_limits * lim)3547848c7085STyrel Datwyler static int ibmvfc_sdev_configure(struct scsi_device *sdev,
3548848c7085STyrel Datwyler 				 struct queue_limits *lim)
3549848c7085STyrel Datwyler {
3550848c7085STyrel Datwyler 	struct Scsi_Host *shost = sdev->host;
3551848c7085STyrel Datwyler 	unsigned long flags = 0;
3552848c7085STyrel Datwyler 
3553848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3554848c7085STyrel Datwyler 	if (sdev->type == TYPE_DISK) {
3555848c7085STyrel Datwyler 		sdev->allow_restart = 1;
3556848c7085STyrel Datwyler 		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
3557848c7085STyrel Datwyler 	}
3558848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3559848c7085STyrel Datwyler 	return 0;
3560848c7085STyrel Datwyler }
3561848c7085STyrel Datwyler 
3562848c7085STyrel Datwyler /**
3563848c7085STyrel Datwyler  * ibmvfc_change_queue_depth - Change the device's queue depth
3564848c7085STyrel Datwyler  * @sdev:	scsi device struct
3565848c7085STyrel Datwyler  * @qdepth:	depth to set
3566848c7085STyrel Datwyler  *
3567848c7085STyrel Datwyler  * Return value:
3568848c7085STyrel Datwyler  * 	actual depth set
3569848c7085STyrel Datwyler  **/
ibmvfc_change_queue_depth(struct scsi_device * sdev,int qdepth)3570848c7085STyrel Datwyler static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth)
3571848c7085STyrel Datwyler {
3572848c7085STyrel Datwyler 	if (qdepth > IBMVFC_MAX_CMDS_PER_LUN)
3573848c7085STyrel Datwyler 		qdepth = IBMVFC_MAX_CMDS_PER_LUN;
3574848c7085STyrel Datwyler 
3575848c7085STyrel Datwyler 	return scsi_change_queue_depth(sdev, qdepth);
3576848c7085STyrel Datwyler }
3577848c7085STyrel Datwyler 
ibmvfc_show_host_partition_name(struct device * dev,struct device_attribute * attr,char * buf)3578848c7085STyrel Datwyler static ssize_t ibmvfc_show_host_partition_name(struct device *dev,
3579848c7085STyrel Datwyler 						 struct device_attribute *attr, char *buf)
3580848c7085STyrel Datwyler {
3581848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3582848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3583848c7085STyrel Datwyler 
3584848c7085STyrel Datwyler 	return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.partition_name);
3585848c7085STyrel Datwyler }
3586848c7085STyrel Datwyler 
ibmvfc_show_host_device_name(struct device * dev,struct device_attribute * attr,char * buf)3587848c7085STyrel Datwyler static ssize_t ibmvfc_show_host_device_name(struct device *dev,
3588848c7085STyrel Datwyler 					    struct device_attribute *attr, char *buf)
3589848c7085STyrel Datwyler {
3590848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3591848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3592848c7085STyrel Datwyler 
3593848c7085STyrel Datwyler 	return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.device_name);
3594848c7085STyrel Datwyler }
3595848c7085STyrel Datwyler 
ibmvfc_show_host_loc_code(struct device * dev,struct device_attribute * attr,char * buf)3596848c7085STyrel Datwyler static ssize_t ibmvfc_show_host_loc_code(struct device *dev,
3597848c7085STyrel Datwyler 					 struct device_attribute *attr, char *buf)
3598848c7085STyrel Datwyler {
3599848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3600848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3601848c7085STyrel Datwyler 
3602848c7085STyrel Datwyler 	return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.port_loc_code);
3603848c7085STyrel Datwyler }
3604848c7085STyrel Datwyler 
ibmvfc_show_host_drc_name(struct device * dev,struct device_attribute * attr,char * buf)3605848c7085STyrel Datwyler static ssize_t ibmvfc_show_host_drc_name(struct device *dev,
3606848c7085STyrel Datwyler 					 struct device_attribute *attr, char *buf)
3607848c7085STyrel Datwyler {
3608848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3609848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3610848c7085STyrel Datwyler 
3611848c7085STyrel Datwyler 	return sysfs_emit(buf, "%s\n", vhost->login_buf->resp.drc_name);
3612848c7085STyrel Datwyler }
3613848c7085STyrel Datwyler 
ibmvfc_show_host_npiv_version(struct device * dev,struct device_attribute * attr,char * buf)3614848c7085STyrel Datwyler static ssize_t ibmvfc_show_host_npiv_version(struct device *dev,
3615848c7085STyrel Datwyler 					     struct device_attribute *attr, char *buf)
3616848c7085STyrel Datwyler {
3617848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3618848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3619848c7085STyrel Datwyler 	return sysfs_emit(buf, "%d\n",
3620848c7085STyrel Datwyler 			  be32_to_cpu(vhost->login_buf->resp.version));
3621848c7085STyrel Datwyler }
3622848c7085STyrel Datwyler 
ibmvfc_show_host_capabilities(struct device * dev,struct device_attribute * attr,char * buf)3623848c7085STyrel Datwyler static ssize_t ibmvfc_show_host_capabilities(struct device *dev,
3624848c7085STyrel Datwyler 					     struct device_attribute *attr, char *buf)
3625848c7085STyrel Datwyler {
3626848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3627848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3628848c7085STyrel Datwyler 	return sysfs_emit(buf, "%llx\n",
3629848c7085STyrel Datwyler 			  be64_to_cpu(vhost->login_buf->resp.capabilities));
3630848c7085STyrel Datwyler }
3631848c7085STyrel Datwyler 
3632848c7085STyrel Datwyler /**
3633848c7085STyrel Datwyler  * ibmvfc_show_log_level - Show the adapter's error logging level
3634848c7085STyrel Datwyler  * @dev:	class device struct
3635848c7085STyrel Datwyler  * @attr:	unused
3636848c7085STyrel Datwyler  * @buf:	buffer
3637848c7085STyrel Datwyler  *
3638848c7085STyrel Datwyler  * Return value:
3639848c7085STyrel Datwyler  * 	number of bytes printed to buffer
3640848c7085STyrel Datwyler  **/
ibmvfc_show_log_level(struct device * dev,struct device_attribute * attr,char * buf)3641848c7085STyrel Datwyler static ssize_t ibmvfc_show_log_level(struct device *dev,
3642848c7085STyrel Datwyler 				     struct device_attribute *attr, char *buf)
3643848c7085STyrel Datwyler {
3644848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3645848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3646848c7085STyrel Datwyler 	unsigned long flags = 0;
3647848c7085STyrel Datwyler 	int len;
3648848c7085STyrel Datwyler 
3649848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3650848c7085STyrel Datwyler 	len = sysfs_emit(buf, "%d\n", vhost->log_level);
3651848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3652848c7085STyrel Datwyler 	return len;
3653848c7085STyrel Datwyler }
3654848c7085STyrel Datwyler 
3655848c7085STyrel Datwyler /**
3656848c7085STyrel Datwyler  * ibmvfc_store_log_level - Change the adapter's error logging level
3657848c7085STyrel Datwyler  * @dev:	class device struct
3658848c7085STyrel Datwyler  * @attr:	unused
3659848c7085STyrel Datwyler  * @buf:	buffer
3660848c7085STyrel Datwyler  * @count:      buffer size
3661848c7085STyrel Datwyler  *
3662848c7085STyrel Datwyler  * Return value:
3663848c7085STyrel Datwyler  * 	number of bytes printed to buffer
3664848c7085STyrel Datwyler  **/
ibmvfc_store_log_level(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3665848c7085STyrel Datwyler static ssize_t ibmvfc_store_log_level(struct device *dev,
3666848c7085STyrel Datwyler 				      struct device_attribute *attr,
3667848c7085STyrel Datwyler 				      const char *buf, size_t count)
3668848c7085STyrel Datwyler {
3669848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3670848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3671848c7085STyrel Datwyler 	unsigned long flags = 0;
3672848c7085STyrel Datwyler 
3673848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3674848c7085STyrel Datwyler 	vhost->log_level = simple_strtoul(buf, NULL, 10);
3675848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3676848c7085STyrel Datwyler 	return strlen(buf);
3677848c7085STyrel Datwyler }
3678848c7085STyrel Datwyler 
ibmvfc_show_scsi_channels(struct device * dev,struct device_attribute * attr,char * buf)3679848c7085STyrel Datwyler static ssize_t ibmvfc_show_scsi_channels(struct device *dev,
3680848c7085STyrel Datwyler 					 struct device_attribute *attr, char *buf)
3681848c7085STyrel Datwyler {
3682848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3683848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3684848c7085STyrel Datwyler 	struct ibmvfc_channels *scsi = &vhost->scsi_scrqs;
3685848c7085STyrel Datwyler 	unsigned long flags = 0;
3686848c7085STyrel Datwyler 	int len;
3687848c7085STyrel Datwyler 
3688848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3689848c7085STyrel Datwyler 	len = sysfs_emit(buf, "%d\n", scsi->desired_queues);
3690848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3691848c7085STyrel Datwyler 	return len;
3692848c7085STyrel Datwyler }
3693848c7085STyrel Datwyler 
ibmvfc_store_scsi_channels(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3694848c7085STyrel Datwyler static ssize_t ibmvfc_store_scsi_channels(struct device *dev,
3695848c7085STyrel Datwyler 					 struct device_attribute *attr,
3696848c7085STyrel Datwyler 					 const char *buf, size_t count)
3697848c7085STyrel Datwyler {
3698848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3699848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3700848c7085STyrel Datwyler 	struct ibmvfc_channels *scsi = &vhost->scsi_scrqs;
3701848c7085STyrel Datwyler 	unsigned long flags = 0;
3702848c7085STyrel Datwyler 	unsigned int channels;
3703848c7085STyrel Datwyler 
3704848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3705848c7085STyrel Datwyler 	channels = simple_strtoul(buf, NULL, 10);
3706848c7085STyrel Datwyler 	scsi->desired_queues = min(channels, shost->nr_hw_queues);
3707848c7085STyrel Datwyler 	ibmvfc_hard_reset_host(vhost);
3708848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3709848c7085STyrel Datwyler 	return strlen(buf);
3710848c7085STyrel Datwyler }
3711848c7085STyrel Datwyler 
3712848c7085STyrel Datwyler static DEVICE_ATTR(partition_name, S_IRUGO, ibmvfc_show_host_partition_name, NULL);
3713848c7085STyrel Datwyler static DEVICE_ATTR(device_name, S_IRUGO, ibmvfc_show_host_device_name, NULL);
3714848c7085STyrel Datwyler static DEVICE_ATTR(port_loc_code, S_IRUGO, ibmvfc_show_host_loc_code, NULL);
3715848c7085STyrel Datwyler static DEVICE_ATTR(drc_name, S_IRUGO, ibmvfc_show_host_drc_name, NULL);
3716848c7085STyrel Datwyler static DEVICE_ATTR(npiv_version, S_IRUGO, ibmvfc_show_host_npiv_version, NULL);
3717848c7085STyrel Datwyler static DEVICE_ATTR(capabilities, S_IRUGO, ibmvfc_show_host_capabilities, NULL);
3718848c7085STyrel Datwyler static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR,
3719848c7085STyrel Datwyler 		   ibmvfc_show_log_level, ibmvfc_store_log_level);
3720848c7085STyrel Datwyler static DEVICE_ATTR(nr_scsi_channels, S_IRUGO | S_IWUSR,
3721848c7085STyrel Datwyler 		   ibmvfc_show_scsi_channels, ibmvfc_store_scsi_channels);
3722848c7085STyrel Datwyler 
3723848c7085STyrel Datwyler #ifdef CONFIG_SCSI_IBMVFC_TRACE
3724848c7085STyrel Datwyler /**
3725848c7085STyrel Datwyler  * ibmvfc_read_trace - Dump the adapter trace
3726848c7085STyrel Datwyler  * @filp:		open sysfs file
3727848c7085STyrel Datwyler  * @kobj:		kobject struct
3728848c7085STyrel Datwyler  * @bin_attr:	bin_attribute struct
3729848c7085STyrel Datwyler  * @buf:		buffer
3730848c7085STyrel Datwyler  * @off:		offset
3731848c7085STyrel Datwyler  * @count:		buffer size
3732848c7085STyrel Datwyler  *
3733848c7085STyrel Datwyler  * Return value:
3734848c7085STyrel Datwyler  *	number of bytes printed to buffer
3735848c7085STyrel Datwyler  **/
ibmvfc_read_trace(struct file * filp,struct kobject * kobj,const struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)3736848c7085STyrel Datwyler static ssize_t ibmvfc_read_trace(struct file *filp, struct kobject *kobj,
3737848c7085STyrel Datwyler 				 const struct bin_attribute *bin_attr,
3738848c7085STyrel Datwyler 				 char *buf, loff_t off, size_t count)
3739848c7085STyrel Datwyler {
3740848c7085STyrel Datwyler 	struct device *dev = kobj_to_dev(kobj);
3741848c7085STyrel Datwyler 	struct Scsi_Host *shost = class_to_shost(dev);
3742848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = shost_priv(shost);
3743848c7085STyrel Datwyler 	unsigned long flags = 0;
3744848c7085STyrel Datwyler 	int size = IBMVFC_TRACE_SIZE;
3745848c7085STyrel Datwyler 	char *src = (char *)vhost->trace;
3746848c7085STyrel Datwyler 
3747848c7085STyrel Datwyler 	if (off > size)
3748848c7085STyrel Datwyler 		return 0;
3749848c7085STyrel Datwyler 	if (off + count > size) {
3750848c7085STyrel Datwyler 		size -= off;
3751848c7085STyrel Datwyler 		count = size;
3752848c7085STyrel Datwyler 	}
3753848c7085STyrel Datwyler 
3754848c7085STyrel Datwyler 	spin_lock_irqsave(shost->host_lock, flags);
3755848c7085STyrel Datwyler 	memcpy(buf, &src[off], count);
3756848c7085STyrel Datwyler 	spin_unlock_irqrestore(shost->host_lock, flags);
3757848c7085STyrel Datwyler 	return count;
3758848c7085STyrel Datwyler }
3759848c7085STyrel Datwyler 
3760848c7085STyrel Datwyler static const struct bin_attribute ibmvfc_trace_attr = {
3761848c7085STyrel Datwyler 	.attr =	{
3762848c7085STyrel Datwyler 		.name = "trace",
3763848c7085STyrel Datwyler 		.mode = S_IRUGO,
3764848c7085STyrel Datwyler 	},
3765848c7085STyrel Datwyler 	.size = 0,
3766848c7085STyrel Datwyler 	.read = ibmvfc_read_trace,
3767848c7085STyrel Datwyler };
3768848c7085STyrel Datwyler #endif
3769848c7085STyrel Datwyler 
3770848c7085STyrel Datwyler static struct attribute *ibmvfc_host_attrs[] = {
3771848c7085STyrel Datwyler 	&dev_attr_partition_name.attr,
3772848c7085STyrel Datwyler 	&dev_attr_device_name.attr,
3773848c7085STyrel Datwyler 	&dev_attr_port_loc_code.attr,
3774848c7085STyrel Datwyler 	&dev_attr_drc_name.attr,
3775848c7085STyrel Datwyler 	&dev_attr_npiv_version.attr,
3776848c7085STyrel Datwyler 	&dev_attr_capabilities.attr,
3777848c7085STyrel Datwyler 	&dev_attr_log_level.attr,
3778848c7085STyrel Datwyler 	&dev_attr_nr_scsi_channels.attr,
3779848c7085STyrel Datwyler 	NULL
3780848c7085STyrel Datwyler };
3781848c7085STyrel Datwyler 
3782848c7085STyrel Datwyler ATTRIBUTE_GROUPS(ibmvfc_host);
3783848c7085STyrel Datwyler 
3784848c7085STyrel Datwyler static const struct scsi_host_template driver_template = {
3785848c7085STyrel Datwyler 	.module = THIS_MODULE,
3786848c7085STyrel Datwyler 	.name = "IBM POWER Virtual FC Adapter",
3787848c7085STyrel Datwyler 	.proc_name = IBMVFC_NAME,
3788848c7085STyrel Datwyler 	.queuecommand = ibmvfc_queuecommand,
3789848c7085STyrel Datwyler 	.eh_timed_out = fc_eh_timed_out,
3790848c7085STyrel Datwyler 	.eh_abort_handler = ibmvfc_eh_abort_handler,
3791848c7085STyrel Datwyler 	.eh_device_reset_handler = ibmvfc_eh_device_reset_handler,
3792848c7085STyrel Datwyler 	.eh_target_reset_handler = ibmvfc_eh_target_reset_handler,
3793848c7085STyrel Datwyler 	.eh_host_reset_handler = ibmvfc_eh_host_reset_handler,
3794848c7085STyrel Datwyler 	.sdev_init = ibmvfc_sdev_init,
3795848c7085STyrel Datwyler 	.sdev_configure = ibmvfc_sdev_configure,
3796848c7085STyrel Datwyler 	.target_alloc = ibmvfc_target_alloc,
3797848c7085STyrel Datwyler 	.scan_finished = ibmvfc_scan_finished,
3798848c7085STyrel Datwyler 	.change_queue_depth = ibmvfc_change_queue_depth,
3799848c7085STyrel Datwyler 	.cmd_per_lun = 16,
3800848c7085STyrel Datwyler 	.can_queue = IBMVFC_MAX_REQUESTS_DEFAULT,
3801848c7085STyrel Datwyler 	.this_id = -1,
3802848c7085STyrel Datwyler 	.sg_tablesize = SG_ALL,
3803848c7085STyrel Datwyler 	.max_sectors = IBMVFC_MAX_SECTORS,
3804848c7085STyrel Datwyler 	.shost_groups = ibmvfc_host_groups,
3805848c7085STyrel Datwyler 	.track_queue_depth = 1,
3806848c7085STyrel Datwyler };
3807848c7085STyrel Datwyler 
3808848c7085STyrel Datwyler /**
3809848c7085STyrel Datwyler  * ibmvfc_next_async_crq - Returns the next entry in async queue
3810848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
3811848c7085STyrel Datwyler  *
3812848c7085STyrel Datwyler  * Returns:
3813848c7085STyrel Datwyler  *	Pointer to next entry in queue / NULL if empty
3814848c7085STyrel Datwyler  **/
ibmvfc_next_async_crq(struct ibmvfc_host * vhost)3815848c7085STyrel Datwyler static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost)
3816848c7085STyrel Datwyler {
3817848c7085STyrel Datwyler 	struct ibmvfc_queue *async_crq = &vhost->async_crq;
3818848c7085STyrel Datwyler 	struct ibmvfc_async_crq *crq;
3819848c7085STyrel Datwyler 
3820848c7085STyrel Datwyler 	crq = &async_crq->msgs.async[async_crq->cur];
3821848c7085STyrel Datwyler 	if (crq->valid & 0x80) {
3822848c7085STyrel Datwyler 		if (++async_crq->cur == async_crq->size)
3823848c7085STyrel Datwyler 			async_crq->cur = 0;
3824848c7085STyrel Datwyler 		rmb();
3825848c7085STyrel Datwyler 	} else
3826848c7085STyrel Datwyler 		crq = NULL;
3827848c7085STyrel Datwyler 
3828848c7085STyrel Datwyler 	return crq;
3829848c7085STyrel Datwyler }
3830848c7085STyrel Datwyler 
3831848c7085STyrel Datwyler /**
3832848c7085STyrel Datwyler  * ibmvfc_next_crq - Returns the next entry in message queue
3833848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
3834848c7085STyrel Datwyler  *
3835848c7085STyrel Datwyler  * Returns:
3836848c7085STyrel Datwyler  *	Pointer to next entry in queue / NULL if empty
3837848c7085STyrel Datwyler  **/
ibmvfc_next_crq(struct ibmvfc_host * vhost)3838848c7085STyrel Datwyler static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost)
3839848c7085STyrel Datwyler {
3840848c7085STyrel Datwyler 	struct ibmvfc_queue *queue = &vhost->crq;
3841848c7085STyrel Datwyler 	struct ibmvfc_crq *crq;
3842848c7085STyrel Datwyler 
3843848c7085STyrel Datwyler 	crq = &queue->msgs.crq[queue->cur];
3844848c7085STyrel Datwyler 	if (crq->valid & 0x80) {
3845848c7085STyrel Datwyler 		if (++queue->cur == queue->size)
3846848c7085STyrel Datwyler 			queue->cur = 0;
3847848c7085STyrel Datwyler 		rmb();
3848848c7085STyrel Datwyler 	} else
3849848c7085STyrel Datwyler 		crq = NULL;
3850848c7085STyrel Datwyler 
3851848c7085STyrel Datwyler 	return crq;
3852848c7085STyrel Datwyler }
3853848c7085STyrel Datwyler 
3854848c7085STyrel Datwyler /**
3855848c7085STyrel Datwyler  * ibmvfc_interrupt - Interrupt handler
3856848c7085STyrel Datwyler  * @irq:		number of irq to handle, not used
3857848c7085STyrel Datwyler  * @dev_instance: ibmvfc_host that received interrupt
3858848c7085STyrel Datwyler  *
3859848c7085STyrel Datwyler  * Returns:
3860848c7085STyrel Datwyler  *	IRQ_HANDLED
3861848c7085STyrel Datwyler  **/
ibmvfc_interrupt(int irq,void * dev_instance)3862848c7085STyrel Datwyler static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance)
3863848c7085STyrel Datwyler {
3864848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance;
3865848c7085STyrel Datwyler 	unsigned long flags;
3866848c7085STyrel Datwyler 
3867848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
3868848c7085STyrel Datwyler 	vio_disable_interrupts(to_vio_dev(vhost->dev));
3869848c7085STyrel Datwyler 	tasklet_schedule(&vhost->tasklet);
3870848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
3871848c7085STyrel Datwyler 	return IRQ_HANDLED;
3872848c7085STyrel Datwyler }
3873848c7085STyrel Datwyler 
3874848c7085STyrel Datwyler /**
3875848c7085STyrel Datwyler  * ibmvfc_tasklet - Interrupt handler tasklet
3876848c7085STyrel Datwyler  * @data:		ibmvfc host struct
3877848c7085STyrel Datwyler  *
3878848c7085STyrel Datwyler  * Returns:
3879848c7085STyrel Datwyler  *	Nothing
3880848c7085STyrel Datwyler  **/
ibmvfc_tasklet(void * data)3881848c7085STyrel Datwyler static void ibmvfc_tasklet(void *data)
3882848c7085STyrel Datwyler {
3883848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = data;
3884848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(vhost->dev);
3885848c7085STyrel Datwyler 	struct ibmvfc_crq *crq;
3886848c7085STyrel Datwyler 	struct ibmvfc_async_crq *async;
3887848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *temp;
3888848c7085STyrel Datwyler 	unsigned long flags;
3889848c7085STyrel Datwyler 	int done = 0;
3890848c7085STyrel Datwyler 	LIST_HEAD(evt_doneq);
3891848c7085STyrel Datwyler 
3892848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
3893848c7085STyrel Datwyler 	spin_lock(vhost->crq.q_lock);
3894848c7085STyrel Datwyler 	while (!done) {
3895848c7085STyrel Datwyler 		/* Pull all the valid messages off the async CRQ */
3896848c7085STyrel Datwyler 		while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
3897848c7085STyrel Datwyler 			ibmvfc_handle_async(async, vhost);
3898848c7085STyrel Datwyler 			async->valid = 0;
3899848c7085STyrel Datwyler 			wmb();
3900848c7085STyrel Datwyler 		}
3901848c7085STyrel Datwyler 
3902848c7085STyrel Datwyler 		/* Pull all the valid messages off the CRQ */
3903848c7085STyrel Datwyler 		while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
3904848c7085STyrel Datwyler 			ibmvfc_handle_crq(crq, vhost, &evt_doneq);
3905848c7085STyrel Datwyler 			crq->valid = 0;
3906848c7085STyrel Datwyler 			wmb();
3907848c7085STyrel Datwyler 		}
3908848c7085STyrel Datwyler 
3909848c7085STyrel Datwyler 		vio_enable_interrupts(vdev);
3910848c7085STyrel Datwyler 		if ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
3911848c7085STyrel Datwyler 			vio_disable_interrupts(vdev);
3912848c7085STyrel Datwyler 			ibmvfc_handle_async(async, vhost);
3913848c7085STyrel Datwyler 			async->valid = 0;
3914848c7085STyrel Datwyler 			wmb();
3915848c7085STyrel Datwyler 		} else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
3916848c7085STyrel Datwyler 			vio_disable_interrupts(vdev);
3917848c7085STyrel Datwyler 			ibmvfc_handle_crq(crq, vhost, &evt_doneq);
3918848c7085STyrel Datwyler 			crq->valid = 0;
3919848c7085STyrel Datwyler 			wmb();
3920848c7085STyrel Datwyler 		} else
3921848c7085STyrel Datwyler 			done = 1;
3922848c7085STyrel Datwyler 	}
3923848c7085STyrel Datwyler 
3924848c7085STyrel Datwyler 	spin_unlock(vhost->crq.q_lock);
3925848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
3926848c7085STyrel Datwyler 
3927848c7085STyrel Datwyler 	list_for_each_entry_safe(evt, temp, &evt_doneq, queue_list) {
3928848c7085STyrel Datwyler 		timer_delete(&evt->timer);
3929848c7085STyrel Datwyler 		list_del(&evt->queue_list);
3930848c7085STyrel Datwyler 		ibmvfc_trc_end(evt);
3931848c7085STyrel Datwyler 		evt->done(evt);
3932848c7085STyrel Datwyler 	}
3933848c7085STyrel Datwyler }
3934848c7085STyrel Datwyler 
ibmvfc_toggle_scrq_irq(struct ibmvfc_queue * scrq,int enable)3935848c7085STyrel Datwyler static int ibmvfc_toggle_scrq_irq(struct ibmvfc_queue *scrq, int enable)
3936848c7085STyrel Datwyler {
3937848c7085STyrel Datwyler 	struct device *dev = scrq->vhost->dev;
3938848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(dev);
3939848c7085STyrel Datwyler 	unsigned long rc;
3940848c7085STyrel Datwyler 	int irq_action = H_ENABLE_VIO_INTERRUPT;
3941848c7085STyrel Datwyler 
3942848c7085STyrel Datwyler 	if (!enable)
3943848c7085STyrel Datwyler 		irq_action = H_DISABLE_VIO_INTERRUPT;
3944848c7085STyrel Datwyler 
3945848c7085STyrel Datwyler 	rc = plpar_hcall_norets(H_VIOCTL, vdev->unit_address, irq_action,
3946848c7085STyrel Datwyler 				scrq->hw_irq, 0, 0);
3947848c7085STyrel Datwyler 
3948848c7085STyrel Datwyler 	if (rc)
3949848c7085STyrel Datwyler 		dev_err(dev, "Couldn't %s sub-crq[%lu] irq. rc=%ld\n",
3950848c7085STyrel Datwyler 			enable ? "enable" : "disable", scrq->hwq_id, rc);
3951848c7085STyrel Datwyler 
3952848c7085STyrel Datwyler 	return rc;
3953848c7085STyrel Datwyler }
3954848c7085STyrel Datwyler 
ibmvfc_handle_scrq(struct ibmvfc_crq * crq,struct ibmvfc_host * vhost,struct list_head * evt_doneq)3955848c7085STyrel Datwyler static void ibmvfc_handle_scrq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost,
3956848c7085STyrel Datwyler 			       struct list_head *evt_doneq)
3957848c7085STyrel Datwyler {
3958848c7085STyrel Datwyler 	struct ibmvfc_event *evt = (struct ibmvfc_event *)be64_to_cpu(crq->ioba);
3959848c7085STyrel Datwyler 
3960848c7085STyrel Datwyler 	switch (crq->valid) {
3961848c7085STyrel Datwyler 	case IBMVFC_CRQ_CMD_RSP:
3962848c7085STyrel Datwyler 		break;
3963848c7085STyrel Datwyler 	case IBMVFC_CRQ_XPORT_EVENT:
3964848c7085STyrel Datwyler 		return;
3965848c7085STyrel Datwyler 	default:
3966848c7085STyrel Datwyler 		dev_err(vhost->dev, "Got and invalid message type 0x%02x\n", crq->valid);
3967848c7085STyrel Datwyler 		return;
3968848c7085STyrel Datwyler 	}
3969848c7085STyrel Datwyler 
3970848c7085STyrel Datwyler 	/* The only kind of payload CRQs we should get are responses to
3971848c7085STyrel Datwyler 	 * things we send. Make sure this response is to something we
3972848c7085STyrel Datwyler 	 * actually sent
3973848c7085STyrel Datwyler 	 */
3974848c7085STyrel Datwyler 	if (unlikely(!ibmvfc_valid_event(&evt->queue->evt_pool, evt))) {
3975848c7085STyrel Datwyler 		dev_err(vhost->dev, "Returned correlation_token 0x%08llx is invalid!\n",
3976848c7085STyrel Datwyler 			crq->ioba);
3977848c7085STyrel Datwyler 		return;
3978848c7085STyrel Datwyler 	}
3979848c7085STyrel Datwyler 
3980848c7085STyrel Datwyler 	if (unlikely(atomic_dec_if_positive(&evt->active))) {
3981848c7085STyrel Datwyler 		dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n",
3982848c7085STyrel Datwyler 			crq->ioba);
3983848c7085STyrel Datwyler 		return;
3984848c7085STyrel Datwyler 	}
3985848c7085STyrel Datwyler 
3986848c7085STyrel Datwyler 	spin_lock(&evt->queue->l_lock);
3987848c7085STyrel Datwyler 	list_move_tail(&evt->queue_list, evt_doneq);
3988848c7085STyrel Datwyler 	spin_unlock(&evt->queue->l_lock);
3989848c7085STyrel Datwyler }
3990848c7085STyrel Datwyler 
ibmvfc_next_scrq(struct ibmvfc_queue * scrq)3991848c7085STyrel Datwyler static struct ibmvfc_crq *ibmvfc_next_scrq(struct ibmvfc_queue *scrq)
3992848c7085STyrel Datwyler {
3993848c7085STyrel Datwyler 	struct ibmvfc_crq *crq;
3994848c7085STyrel Datwyler 
3995848c7085STyrel Datwyler 	crq = &scrq->msgs.scrq[scrq->cur].crq;
3996848c7085STyrel Datwyler 	if (crq->valid & 0x80) {
3997848c7085STyrel Datwyler 		if (++scrq->cur == scrq->size)
3998848c7085STyrel Datwyler 			scrq->cur = 0;
3999848c7085STyrel Datwyler 		rmb();
4000848c7085STyrel Datwyler 	} else
4001848c7085STyrel Datwyler 		crq = NULL;
4002848c7085STyrel Datwyler 
4003848c7085STyrel Datwyler 	return crq;
4004848c7085STyrel Datwyler }
4005848c7085STyrel Datwyler 
ibmvfc_drain_sub_crq(struct ibmvfc_queue * scrq)4006848c7085STyrel Datwyler static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq)
4007848c7085STyrel Datwyler {
4008848c7085STyrel Datwyler 	struct ibmvfc_crq *crq;
4009848c7085STyrel Datwyler 	struct ibmvfc_event *evt, *temp;
4010848c7085STyrel Datwyler 	unsigned long flags;
4011848c7085STyrel Datwyler 	int done = 0;
4012848c7085STyrel Datwyler 	LIST_HEAD(evt_doneq);
4013848c7085STyrel Datwyler 
4014848c7085STyrel Datwyler 	spin_lock_irqsave(scrq->q_lock, flags);
4015848c7085STyrel Datwyler 	while (!done) {
4016848c7085STyrel Datwyler 		while ((crq = ibmvfc_next_scrq(scrq)) != NULL) {
4017848c7085STyrel Datwyler 			ibmvfc_handle_scrq(crq, scrq->vhost, &evt_doneq);
4018848c7085STyrel Datwyler 			crq->valid = 0;
4019848c7085STyrel Datwyler 			wmb();
4020848c7085STyrel Datwyler 		}
4021848c7085STyrel Datwyler 
4022848c7085STyrel Datwyler 		ibmvfc_toggle_scrq_irq(scrq, 1);
4023848c7085STyrel Datwyler 		if ((crq = ibmvfc_next_scrq(scrq)) != NULL) {
4024848c7085STyrel Datwyler 			ibmvfc_toggle_scrq_irq(scrq, 0);
4025848c7085STyrel Datwyler 			ibmvfc_handle_scrq(crq, scrq->vhost, &evt_doneq);
4026848c7085STyrel Datwyler 			crq->valid = 0;
4027848c7085STyrel Datwyler 			wmb();
4028848c7085STyrel Datwyler 		} else
4029848c7085STyrel Datwyler 			done = 1;
4030848c7085STyrel Datwyler 	}
4031848c7085STyrel Datwyler 	spin_unlock_irqrestore(scrq->q_lock, flags);
4032848c7085STyrel Datwyler 
4033848c7085STyrel Datwyler 	list_for_each_entry_safe(evt, temp, &evt_doneq, queue_list) {
4034848c7085STyrel Datwyler 		timer_delete(&evt->timer);
4035848c7085STyrel Datwyler 		list_del(&evt->queue_list);
4036848c7085STyrel Datwyler 		ibmvfc_trc_end(evt);
4037848c7085STyrel Datwyler 		evt->done(evt);
4038848c7085STyrel Datwyler 	}
4039848c7085STyrel Datwyler }
4040848c7085STyrel Datwyler 
ibmvfc_interrupt_mq(int irq,void * scrq_instance)4041848c7085STyrel Datwyler static irqreturn_t ibmvfc_interrupt_mq(int irq, void *scrq_instance)
4042848c7085STyrel Datwyler {
4043848c7085STyrel Datwyler 	struct ibmvfc_queue *scrq = (struct ibmvfc_queue *)scrq_instance;
4044848c7085STyrel Datwyler 
4045848c7085STyrel Datwyler 	ibmvfc_toggle_scrq_irq(scrq, 0);
4046848c7085STyrel Datwyler 	ibmvfc_drain_sub_crq(scrq);
4047848c7085STyrel Datwyler 
4048848c7085STyrel Datwyler 	return IRQ_HANDLED;
4049848c7085STyrel Datwyler }
4050848c7085STyrel Datwyler 
4051848c7085STyrel Datwyler /**
4052848c7085STyrel Datwyler  * ibmvfc_init_tgt - Set the next init job step for the target
4053848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4054848c7085STyrel Datwyler  * @job_step:	job step to perform
4055848c7085STyrel Datwyler  *
4056848c7085STyrel Datwyler  **/
ibmvfc_init_tgt(struct ibmvfc_target * tgt,void (* job_step)(struct ibmvfc_target *))4057848c7085STyrel Datwyler static void ibmvfc_init_tgt(struct ibmvfc_target *tgt,
4058848c7085STyrel Datwyler 			    void (*job_step) (struct ibmvfc_target *))
4059848c7085STyrel Datwyler {
4060848c7085STyrel Datwyler 	if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT))
4061848c7085STyrel Datwyler 		tgt->job_step = job_step;
4062848c7085STyrel Datwyler 	wake_up(&tgt->vhost->work_wait_q);
4063848c7085STyrel Datwyler }
4064848c7085STyrel Datwyler 
4065848c7085STyrel Datwyler /**
4066848c7085STyrel Datwyler  * ibmvfc_retry_tgt_init - Attempt to retry a step in target initialization
4067848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4068848c7085STyrel Datwyler  * @job_step:	initialization job step
4069848c7085STyrel Datwyler  *
4070848c7085STyrel Datwyler  * Returns: 1 if step will be retried / 0 if not
4071848c7085STyrel Datwyler  *
4072848c7085STyrel Datwyler  **/
ibmvfc_retry_tgt_init(struct ibmvfc_target * tgt,void (* job_step)(struct ibmvfc_target *))4073848c7085STyrel Datwyler static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
4074848c7085STyrel Datwyler 				  void (*job_step) (struct ibmvfc_target *))
4075848c7085STyrel Datwyler {
4076848c7085STyrel Datwyler 	if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) {
4077848c7085STyrel Datwyler 		ibmvfc_del_tgt(tgt);
4078848c7085STyrel Datwyler 		wake_up(&tgt->vhost->work_wait_q);
4079848c7085STyrel Datwyler 		return 0;
4080848c7085STyrel Datwyler 	} else
4081848c7085STyrel Datwyler 		ibmvfc_init_tgt(tgt, job_step);
4082848c7085STyrel Datwyler 	return 1;
4083848c7085STyrel Datwyler }
4084848c7085STyrel Datwyler 
4085848c7085STyrel Datwyler /* Defined in FC-LS */
4086848c7085STyrel Datwyler static const struct {
4087848c7085STyrel Datwyler 	int code;
4088848c7085STyrel Datwyler 	int retry;
4089848c7085STyrel Datwyler 	int logged_in;
4090848c7085STyrel Datwyler } prli_rsp [] = {
4091848c7085STyrel Datwyler 	{ 0, 1, 0 },
4092848c7085STyrel Datwyler 	{ 1, 0, 1 },
4093848c7085STyrel Datwyler 	{ 2, 1, 0 },
4094848c7085STyrel Datwyler 	{ 3, 1, 0 },
4095848c7085STyrel Datwyler 	{ 4, 0, 0 },
4096848c7085STyrel Datwyler 	{ 5, 0, 0 },
4097848c7085STyrel Datwyler 	{ 6, 0, 1 },
4098848c7085STyrel Datwyler 	{ 7, 0, 0 },
4099848c7085STyrel Datwyler 	{ 8, 1, 0 },
4100848c7085STyrel Datwyler };
4101848c7085STyrel Datwyler 
4102848c7085STyrel Datwyler /**
4103848c7085STyrel Datwyler  * ibmvfc_get_prli_rsp - Find PRLI response index
4104848c7085STyrel Datwyler  * @flags:	PRLI response flags
4105848c7085STyrel Datwyler  *
4106848c7085STyrel Datwyler  **/
ibmvfc_get_prli_rsp(u16 flags)4107848c7085STyrel Datwyler static int ibmvfc_get_prli_rsp(u16 flags)
4108848c7085STyrel Datwyler {
4109848c7085STyrel Datwyler 	int i;
4110848c7085STyrel Datwyler 	int code = (flags & 0x0f00) >> 8;
4111848c7085STyrel Datwyler 
4112848c7085STyrel Datwyler 	for (i = 0; i < ARRAY_SIZE(prli_rsp); i++)
4113848c7085STyrel Datwyler 		if (prli_rsp[i].code == code)
4114848c7085STyrel Datwyler 			return i;
4115848c7085STyrel Datwyler 
4116848c7085STyrel Datwyler 	return 0;
4117848c7085STyrel Datwyler }
4118848c7085STyrel Datwyler 
4119848c7085STyrel Datwyler /**
4120848c7085STyrel Datwyler  * ibmvfc_tgt_prli_done - Completion handler for Process Login
4121848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4122848c7085STyrel Datwyler  *
4123848c7085STyrel Datwyler  **/
ibmvfc_tgt_prli_done(struct ibmvfc_event * evt)4124848c7085STyrel Datwyler static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
4125848c7085STyrel Datwyler {
4126848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4127848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4128848c7085STyrel Datwyler 	struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli;
4129848c7085STyrel Datwyler 	struct ibmvfc_prli_svc_parms *parms = &rsp->parms;
4130848c7085STyrel Datwyler 	u32 status = be16_to_cpu(rsp->common.status);
4131848c7085STyrel Datwyler 	int index, level = IBMVFC_DEFAULT_LOG_LEVEL;
4132848c7085STyrel Datwyler 
4133848c7085STyrel Datwyler 	vhost->discovery_threads--;
4134848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4135848c7085STyrel Datwyler 	switch (status) {
4136848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
4137d11c05ddSTyrel Datwyler 		tgt_dbg(tgt, "%s Process Login succeeded: %X %02X %04X\n",
4138d11c05ddSTyrel Datwyler 			proto_type[tgt->protocol], parms->type, parms->flags,
4139d11c05ddSTyrel Datwyler 			parms->service_parms);
4140848c7085STyrel Datwyler 
4141848c7085STyrel Datwyler 		index = ibmvfc_get_prli_rsp(be16_to_cpu(parms->flags));
4142d11c05ddSTyrel Datwyler 		if (parms->type == IBMVFC_SCSI_FCP_TYPE) {
4143848c7085STyrel Datwyler 			if (prli_rsp[index].logged_in) {
4144848c7085STyrel Datwyler 				if (be16_to_cpu(parms->flags) & IBMVFC_PRLI_EST_IMG_PAIR) {
4145848c7085STyrel Datwyler 					tgt->need_login = 0;
4146848c7085STyrel Datwyler 					tgt->ids.roles = 0;
4147848c7085STyrel Datwyler 					if (be32_to_cpu(parms->service_parms) & IBMVFC_PRLI_TARGET_FUNC)
4148848c7085STyrel Datwyler 						tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET;
4149848c7085STyrel Datwyler 					if (be32_to_cpu(parms->service_parms) & IBMVFC_PRLI_INITIATOR_FUNC)
4150848c7085STyrel Datwyler 						tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
4151848c7085STyrel Datwyler 					tgt->add_rport = 1;
4152848c7085STyrel Datwyler 				} else
4153848c7085STyrel Datwyler 					ibmvfc_del_tgt(tgt);
4154848c7085STyrel Datwyler 			} else if (prli_rsp[index].retry)
4155848c7085STyrel Datwyler 				ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
4156848c7085STyrel Datwyler 			else
4157848c7085STyrel Datwyler 				ibmvfc_del_tgt(tgt);
4158d11c05ddSTyrel Datwyler 		} else if (parms->type == IBMVFC_NVME_FCP_TYPE) {
4159d11c05ddSTyrel Datwyler 			if (prli_rsp[index].logged_in) {
4160d11c05ddSTyrel Datwyler 				/* For FC-NVMe PRLI the Image Pair field is always set to zero (see 6.3.3) */
4161d11c05ddSTyrel Datwyler 				tgt->need_login = 0;
4162d11c05ddSTyrel Datwyler 				tgt->ids.roles = 0;
4163d11c05ddSTyrel Datwyler 				if (be32_to_cpu(parms->service_parms) & IBMVFC_PRLI_NVME_TARGET)
4164d11c05ddSTyrel Datwyler 					tgt->ids.roles |= FC_PORT_ROLE_NVME_TARGET;
4165d11c05ddSTyrel Datwyler 				if (be32_to_cpu(parms->service_parms) & IBMVFC_PRLI_NVME_INITIATOR)
4166d11c05ddSTyrel Datwyler 					tgt->ids.roles |= FC_PORT_ROLE_NVME_INITIATOR;
4167d11c05ddSTyrel Datwyler 				if (be32_to_cpu(parms->service_parms) & IBMVFC_PRLI_NVME_DISCOVERY)
4168d11c05ddSTyrel Datwyler 					tgt->ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY;
4169d11c05ddSTyrel Datwyler 				tgt->add_rport = 1;
4170d11c05ddSTyrel Datwyler 			} else if (prli_rsp[index].retry)
4171d11c05ddSTyrel Datwyler 				ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
4172d11c05ddSTyrel Datwyler 			else
4173d11c05ddSTyrel Datwyler 				ibmvfc_del_tgt(tgt);
4174848c7085STyrel Datwyler 		} else
4175848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4176848c7085STyrel Datwyler 		break;
4177848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
4178848c7085STyrel Datwyler 		break;
4179848c7085STyrel Datwyler 	case IBMVFC_MAD_CRQ_ERROR:
4180848c7085STyrel Datwyler 		ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
4181848c7085STyrel Datwyler 		break;
4182848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
4183848c7085STyrel Datwyler 	default:
4184848c7085STyrel Datwyler 		if ((be16_to_cpu(rsp->status) & IBMVFC_VIOS_FAILURE) &&
4185848c7085STyrel Datwyler 		     be16_to_cpu(rsp->error) == IBMVFC_PLOGI_REQUIRED)
4186848c7085STyrel Datwyler 			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
4187848c7085STyrel Datwyler 		else if (tgt->logo_rcvd)
4188848c7085STyrel Datwyler 			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
4189848c7085STyrel Datwyler 		else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
4190848c7085STyrel Datwyler 			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
4191848c7085STyrel Datwyler 		else
4192848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4193848c7085STyrel Datwyler 
4194d11c05ddSTyrel Datwyler 		tgt_log(tgt, level, "%s Process Login failed: %s (%x:%x) rc=0x%02X\n",
4195d11c05ddSTyrel Datwyler 			proto_type[tgt->protocol], ibmvfc_get_cmd_error(be16_to_cpu(rsp->status),
4196d11c05ddSTyrel Datwyler 			be16_to_cpu(rsp->error)), be16_to_cpu(rsp->status),
4197d11c05ddSTyrel Datwyler 			be16_to_cpu(rsp->error), status);
4198848c7085STyrel Datwyler 		break;
4199848c7085STyrel Datwyler 	}
4200848c7085STyrel Datwyler 
4201848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4202848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4203848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4204848c7085STyrel Datwyler }
4205848c7085STyrel Datwyler 
4206848c7085STyrel Datwyler /**
4207848c7085STyrel Datwyler  * ibmvfc_tgt_send_prli - Send a process login
4208848c7085STyrel Datwyler  * @tgt:	ibmvfc target struct
4209848c7085STyrel Datwyler  *
4210848c7085STyrel Datwyler  **/
ibmvfc_tgt_send_prli(struct ibmvfc_target * tgt)4211848c7085STyrel Datwyler static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt)
4212848c7085STyrel Datwyler {
4213848c7085STyrel Datwyler 	struct ibmvfc_process_login *prli;
4214848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4215848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4216848c7085STyrel Datwyler 
4217848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4218848c7085STyrel Datwyler 		return;
4219848c7085STyrel Datwyler 
4220848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4221848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4222848c7085STyrel Datwyler 	if (!evt) {
4223848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4224848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4225848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4226848c7085STyrel Datwyler 		return;
4227848c7085STyrel Datwyler 	}
4228848c7085STyrel Datwyler 	vhost->discovery_threads++;
4229848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT);
4230848c7085STyrel Datwyler 	evt->tgt = tgt;
4231848c7085STyrel Datwyler 	prli = &evt->iu.prli;
4232848c7085STyrel Datwyler 	memset(prli, 0, sizeof(*prli));
4233848c7085STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) {
4234848c7085STyrel Datwyler 		prli->common.version = cpu_to_be32(2);
4235848c7085STyrel Datwyler 		prli->target_wwpn = cpu_to_be64(tgt->wwpn);
4236848c7085STyrel Datwyler 	} else {
4237848c7085STyrel Datwyler 		prli->common.version = cpu_to_be32(1);
4238848c7085STyrel Datwyler 	}
4239d11c05ddSTyrel Datwyler 	if (tgt->protocol == IBMVFC_PROTO_SCSI) {
4240848c7085STyrel Datwyler 		prli->common.opcode = cpu_to_be32(IBMVFC_PROCESS_LOGIN);
4241848c7085STyrel Datwyler 		prli->parms.type = IBMVFC_SCSI_FCP_TYPE;
4242848c7085STyrel Datwyler 		prli->parms.flags = cpu_to_be16(IBMVFC_PRLI_EST_IMG_PAIR);
4243848c7085STyrel Datwyler 		prli->parms.service_parms = cpu_to_be32(IBMVFC_PRLI_INITIATOR_FUNC);
4244848c7085STyrel Datwyler 		prli->parms.service_parms |= cpu_to_be32(IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED);
4245848c7085STyrel Datwyler 
4246848c7085STyrel Datwyler 		if (cls3_error)
4247848c7085STyrel Datwyler 			prli->parms.service_parms |= cpu_to_be32(IBMVFC_PRLI_RETRY);
4248d11c05ddSTyrel Datwyler 	} else {
4249d11c05ddSTyrel Datwyler 		prli->common.opcode = cpu_to_be32(IBMVFC_NVMF_PROCESS_LOGIN);
4250d11c05ddSTyrel Datwyler 		prli->parms.type = IBMVFC_NVME_FCP_TYPE;
4251d11c05ddSTyrel Datwyler 		prli->parms.service_parms = cpu_to_be32(IBMVFC_PRLI_NVME_INITIATOR);
4252d11c05ddSTyrel Datwyler 	}
4253d11c05ddSTyrel Datwyler 	prli->common.length = cpu_to_be16(sizeof(*prli));
4254d11c05ddSTyrel Datwyler 	prli->scsi_id = cpu_to_be64(tgt->scsi_id);
4255848c7085STyrel Datwyler 
4256848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
4257848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
4258848c7085STyrel Datwyler 		vhost->discovery_threads--;
4259848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4260848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4261848c7085STyrel Datwyler 	} else
4262d11c05ddSTyrel Datwyler 		tgt_dbg(tgt, "%s Sent process login\n", proto_type[tgt->protocol]);
4263848c7085STyrel Datwyler }
4264848c7085STyrel Datwyler 
4265848c7085STyrel Datwyler /**
4266848c7085STyrel Datwyler  * ibmvfc_tgt_plogi_done - Completion handler for Port Login
4267848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4268848c7085STyrel Datwyler  *
4269848c7085STyrel Datwyler  **/
ibmvfc_tgt_plogi_done(struct ibmvfc_event * evt)4270848c7085STyrel Datwyler static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
4271848c7085STyrel Datwyler {
4272848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4273848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4274848c7085STyrel Datwyler 	struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi;
4275848c7085STyrel Datwyler 	u32 status = be16_to_cpu(rsp->common.status);
4276848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
4277848c7085STyrel Datwyler 
4278848c7085STyrel Datwyler 	vhost->discovery_threads--;
4279848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4280848c7085STyrel Datwyler 	switch (status) {
4281848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
42824bc896bfSTyrel Datwyler 		tgt_dbg(tgt, "%s Port Login succeeded\n", proto_type[tgt->protocol]);
4283848c7085STyrel Datwyler 		if (tgt->ids.port_name &&
4284848c7085STyrel Datwyler 		    tgt->ids.port_name != wwn_to_u64(rsp->service_parms.port_name)) {
4285848c7085STyrel Datwyler 			vhost->reinit = 1;
4286848c7085STyrel Datwyler 			tgt_dbg(tgt, "Port re-init required\n");
4287848c7085STyrel Datwyler 			break;
4288848c7085STyrel Datwyler 		}
4289848c7085STyrel Datwyler 		tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name);
4290848c7085STyrel Datwyler 		tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name);
4291848c7085STyrel Datwyler 		tgt->ids.port_id = tgt->scsi_id;
4292848c7085STyrel Datwyler 		memcpy(&tgt->service_parms, &rsp->service_parms,
4293848c7085STyrel Datwyler 		       sizeof(tgt->service_parms));
4294848c7085STyrel Datwyler 		memcpy(&tgt->service_parms_change, &rsp->service_parms_change,
4295848c7085STyrel Datwyler 		       sizeof(tgt->service_parms_change));
4296848c7085STyrel Datwyler 		ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli);
4297848c7085STyrel Datwyler 		break;
4298848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
4299848c7085STyrel Datwyler 		break;
4300848c7085STyrel Datwyler 	case IBMVFC_MAD_CRQ_ERROR:
4301848c7085STyrel Datwyler 		ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
4302848c7085STyrel Datwyler 		break;
4303848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
4304848c7085STyrel Datwyler 	default:
4305848c7085STyrel Datwyler 		if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
4306848c7085STyrel Datwyler 			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
4307848c7085STyrel Datwyler 		else
4308848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4309848c7085STyrel Datwyler 
43104bc896bfSTyrel Datwyler 		tgt_log(tgt, level, "%s Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
43114bc896bfSTyrel Datwyler 			proto_type[tgt->protocol], ibmvfc_get_cmd_error(be16_to_cpu(rsp->status),
43124bc896bfSTyrel Datwyler 			be16_to_cpu(rsp->error)), be16_to_cpu(rsp->status), be16_to_cpu(rsp->error),
4313848c7085STyrel Datwyler 			ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), be16_to_cpu(rsp->fc_type),
4314848c7085STyrel Datwyler 			ibmvfc_get_ls_explain(be16_to_cpu(rsp->fc_explain)), be16_to_cpu(rsp->fc_explain), status);
4315848c7085STyrel Datwyler 		break;
4316848c7085STyrel Datwyler 	}
4317848c7085STyrel Datwyler 
4318848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4319848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4320848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4321848c7085STyrel Datwyler }
4322848c7085STyrel Datwyler 
4323848c7085STyrel Datwyler /**
4324848c7085STyrel Datwyler  * ibmvfc_tgt_send_plogi - Send PLOGI to the specified target
4325848c7085STyrel Datwyler  * @tgt:	ibmvfc target struct
4326848c7085STyrel Datwyler  *
4327848c7085STyrel Datwyler  **/
ibmvfc_tgt_send_plogi(struct ibmvfc_target * tgt)4328848c7085STyrel Datwyler static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt)
4329848c7085STyrel Datwyler {
4330848c7085STyrel Datwyler 	struct ibmvfc_port_login *plogi;
4331848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4332848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4333848c7085STyrel Datwyler 
4334848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4335848c7085STyrel Datwyler 		return;
4336848c7085STyrel Datwyler 
4337848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4338848c7085STyrel Datwyler 	tgt->logo_rcvd = 0;
4339848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4340848c7085STyrel Datwyler 	if (!evt) {
4341848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4342848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4343848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4344848c7085STyrel Datwyler 		return;
4345848c7085STyrel Datwyler 	}
4346848c7085STyrel Datwyler 	vhost->discovery_threads++;
4347848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
4348848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT);
4349848c7085STyrel Datwyler 	evt->tgt = tgt;
4350848c7085STyrel Datwyler 	plogi = &evt->iu.plogi;
4351848c7085STyrel Datwyler 	memset(plogi, 0, sizeof(*plogi));
4352848c7085STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) {
4353848c7085STyrel Datwyler 		plogi->common.version = cpu_to_be32(2);
4354848c7085STyrel Datwyler 		plogi->target_wwpn = cpu_to_be64(tgt->wwpn);
4355848c7085STyrel Datwyler 	} else {
4356848c7085STyrel Datwyler 		plogi->common.version = cpu_to_be32(1);
4357848c7085STyrel Datwyler 	}
43584bc896bfSTyrel Datwyler 	if (tgt->protocol == IBMVFC_PROTO_SCSI)
4359848c7085STyrel Datwyler 		plogi->common.opcode = cpu_to_be32(IBMVFC_PORT_LOGIN);
43604bc896bfSTyrel Datwyler 	else
43614bc896bfSTyrel Datwyler 		plogi->common.opcode = cpu_to_be32(IBMVFC_NVMF_PORT_LOGIN);
4362848c7085STyrel Datwyler 	plogi->common.length = cpu_to_be16(sizeof(*plogi));
4363848c7085STyrel Datwyler 	plogi->scsi_id = cpu_to_be64(tgt->scsi_id);
4364848c7085STyrel Datwyler 
4365848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
4366848c7085STyrel Datwyler 		vhost->discovery_threads--;
4367848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4368848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4369848c7085STyrel Datwyler 	} else
43704bc896bfSTyrel Datwyler 		tgt_dbg(tgt, "Sent %s port login\n", proto_type[tgt->protocol]);
4371848c7085STyrel Datwyler }
4372848c7085STyrel Datwyler 
4373848c7085STyrel Datwyler /**
4374848c7085STyrel Datwyler  * ibmvfc_tgt_implicit_logout_done - Completion handler for Implicit Logout MAD
4375848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4376848c7085STyrel Datwyler  *
4377848c7085STyrel Datwyler  **/
ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event * evt)4378848c7085STyrel Datwyler static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt)
4379848c7085STyrel Datwyler {
4380848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4381848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4382848c7085STyrel Datwyler 	struct ibmvfc_implicit_logout *rsp = &evt->xfer_iu->implicit_logout;
4383848c7085STyrel Datwyler 	u32 status = be16_to_cpu(rsp->common.status);
4384848c7085STyrel Datwyler 
4385848c7085STyrel Datwyler 	vhost->discovery_threads--;
4386848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4387848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4388848c7085STyrel Datwyler 
4389848c7085STyrel Datwyler 	switch (status) {
4390848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
4391577608a2STyrel Datwyler 		tgt_dbg(tgt, "%s Implicit Logout succeeded\n", proto_type[tgt->protocol]);
4392848c7085STyrel Datwyler 		break;
4393848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
4394848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4395848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
4396848c7085STyrel Datwyler 		return;
4397848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
4398848c7085STyrel Datwyler 	default:
4399577608a2STyrel Datwyler 		tgt_err(tgt, "%s Implicit Logout failed: rc=0x%02X\n",
4400577608a2STyrel Datwyler 			proto_type[tgt->protocol], status);
4401848c7085STyrel Datwyler 		break;
4402848c7085STyrel Datwyler 	}
4403848c7085STyrel Datwyler 
4404848c7085STyrel Datwyler 	ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi);
4405848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4406848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4407848c7085STyrel Datwyler }
4408848c7085STyrel Datwyler 
4409848c7085STyrel Datwyler /**
4410848c7085STyrel Datwyler  * __ibmvfc_tgt_get_implicit_logout_evt - Allocate and init an event for implicit logout
4411848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4412848c7085STyrel Datwyler  * @done:		Routine to call when the event is responded to
4413848c7085STyrel Datwyler  *
4414848c7085STyrel Datwyler  * Returns:
4415848c7085STyrel Datwyler  *	Allocated and initialized ibmvfc_event struct
4416848c7085STyrel Datwyler  **/
__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_target * tgt,void (* done)(struct ibmvfc_event *))4417848c7085STyrel Datwyler static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_target *tgt,
4418848c7085STyrel Datwyler 								 void (*done) (struct ibmvfc_event *))
4419848c7085STyrel Datwyler {
4420848c7085STyrel Datwyler 	struct ibmvfc_implicit_logout *mad;
4421848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4422848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4423848c7085STyrel Datwyler 
4424848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4425848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4426848c7085STyrel Datwyler 	if (!evt)
4427848c7085STyrel Datwyler 		return NULL;
4428848c7085STyrel Datwyler 	ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT);
4429848c7085STyrel Datwyler 	evt->tgt = tgt;
4430848c7085STyrel Datwyler 	mad = &evt->iu.implicit_logout;
4431848c7085STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
4432848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
4433577608a2STyrel Datwyler 	if (tgt->protocol == IBMVFC_PROTO_SCSI)
4434848c7085STyrel Datwyler 		mad->common.opcode = cpu_to_be32(IBMVFC_IMPLICIT_LOGOUT);
4435577608a2STyrel Datwyler 	else
4436577608a2STyrel Datwyler 		mad->common.opcode = cpu_to_be32(IBMVFC_NVMF_IMPLICIT_LOGOUT);
4437848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad));
4438848c7085STyrel Datwyler 	mad->old_scsi_id = cpu_to_be64(tgt->scsi_id);
4439848c7085STyrel Datwyler 	return evt;
4440848c7085STyrel Datwyler }
4441848c7085STyrel Datwyler 
4442848c7085STyrel Datwyler /**
4443848c7085STyrel Datwyler  * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target
4444848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4445848c7085STyrel Datwyler  *
4446848c7085STyrel Datwyler  **/
ibmvfc_tgt_implicit_logout(struct ibmvfc_target * tgt)4447848c7085STyrel Datwyler static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
4448848c7085STyrel Datwyler {
4449848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4450848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4451848c7085STyrel Datwyler 
4452848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4453848c7085STyrel Datwyler 		return;
4454848c7085STyrel Datwyler 
4455848c7085STyrel Datwyler 	vhost->discovery_threads++;
4456848c7085STyrel Datwyler 	evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt,
4457848c7085STyrel Datwyler 						   ibmvfc_tgt_implicit_logout_done);
4458848c7085STyrel Datwyler 	if (!evt) {
4459848c7085STyrel Datwyler 		vhost->discovery_threads--;
4460848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4461848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4462848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4463848c7085STyrel Datwyler 		return;
4464848c7085STyrel Datwyler 	}
4465848c7085STyrel Datwyler 
4466848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
4467848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
4468848c7085STyrel Datwyler 		vhost->discovery_threads--;
4469848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4470848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4471848c7085STyrel Datwyler 	} else
4472577608a2STyrel Datwyler 		tgt_dbg(tgt, "%s Sent Implicit Logout\n", proto_type[tgt->protocol]);
4473848c7085STyrel Datwyler }
4474848c7085STyrel Datwyler 
4475848c7085STyrel Datwyler /**
4476848c7085STyrel Datwyler  * ibmvfc_tgt_implicit_logout_and_del_done - Completion handler for Implicit Logout MAD
4477848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4478848c7085STyrel Datwyler  *
4479848c7085STyrel Datwyler  **/
ibmvfc_tgt_implicit_logout_and_del_done(struct ibmvfc_event * evt)4480848c7085STyrel Datwyler static void ibmvfc_tgt_implicit_logout_and_del_done(struct ibmvfc_event *evt)
4481848c7085STyrel Datwyler {
4482848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4483848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4484848c7085STyrel Datwyler 	struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
4485848c7085STyrel Datwyler 	u32 status = be16_to_cpu(mad->common.status);
4486848c7085STyrel Datwyler 
4487848c7085STyrel Datwyler 	vhost->discovery_threads--;
4488848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4489848c7085STyrel Datwyler 
4490848c7085STyrel Datwyler 	/*
4491848c7085STyrel Datwyler 	 * If our state is IBMVFC_HOST_OFFLINE, we could be unloading the
4492848c7085STyrel Datwyler 	 * driver in which case we need to free up all the targets. If we are
4493848c7085STyrel Datwyler 	 * not unloading, we will still go through a hard reset to get out of
4494848c7085STyrel Datwyler 	 * offline state, so there is no need to track the old targets in that
4495848c7085STyrel Datwyler 	 * case.
4496848c7085STyrel Datwyler 	 */
4497848c7085STyrel Datwyler 	if (status == IBMVFC_MAD_SUCCESS || vhost->state == IBMVFC_HOST_OFFLINE)
4498848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
4499848c7085STyrel Datwyler 	else
4500848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT);
4501848c7085STyrel Datwyler 
4502577608a2STyrel Datwyler 	tgt_dbg(tgt, "%s Implicit Logout %s\n", proto_type[tgt->protocol],
4503577608a2STyrel Datwyler 		(status == IBMVFC_MAD_SUCCESS) ? "succeeded" : "failed");
4504848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4505848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4506848c7085STyrel Datwyler }
4507848c7085STyrel Datwyler 
4508848c7085STyrel Datwyler /**
4509848c7085STyrel Datwyler  * ibmvfc_tgt_implicit_logout_and_del - Initiate an Implicit Logout for specified target
4510848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4511848c7085STyrel Datwyler  *
4512848c7085STyrel Datwyler  **/
ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target * tgt)4513848c7085STyrel Datwyler static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *tgt)
4514848c7085STyrel Datwyler {
4515848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4516848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4517848c7085STyrel Datwyler 
4518848c7085STyrel Datwyler 	if (!vhost->logged_in) {
4519848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
4520848c7085STyrel Datwyler 		return;
4521848c7085STyrel Datwyler 	}
4522848c7085STyrel Datwyler 
4523848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4524848c7085STyrel Datwyler 		return;
4525848c7085STyrel Datwyler 
4526848c7085STyrel Datwyler 	vhost->discovery_threads++;
4527848c7085STyrel Datwyler 	evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt,
4528848c7085STyrel Datwyler 						   ibmvfc_tgt_implicit_logout_and_del_done);
4529848c7085STyrel Datwyler 
4530848c7085STyrel Datwyler 	if (!evt) {
4531848c7085STyrel Datwyler 		vhost->discovery_threads--;
4532848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4533848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4534848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4535848c7085STyrel Datwyler 		return;
4536848c7085STyrel Datwyler 	}
4537848c7085STyrel Datwyler 
4538848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT);
4539848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
4540848c7085STyrel Datwyler 		vhost->discovery_threads--;
4541848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
4542848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4543848c7085STyrel Datwyler 	} else
4544577608a2STyrel Datwyler 		tgt_dbg(tgt, "%s Sent Implicit Logout\n", proto_type[tgt->protocol]);
4545848c7085STyrel Datwyler }
4546848c7085STyrel Datwyler 
4547848c7085STyrel Datwyler /**
4548848c7085STyrel Datwyler  * ibmvfc_tgt_move_login_done - Completion handler for Move Login
4549848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4550848c7085STyrel Datwyler  *
4551848c7085STyrel Datwyler  **/
ibmvfc_tgt_move_login_done(struct ibmvfc_event * evt)4552848c7085STyrel Datwyler static void ibmvfc_tgt_move_login_done(struct ibmvfc_event *evt)
4553848c7085STyrel Datwyler {
4554848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4555848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4556848c7085STyrel Datwyler 	struct ibmvfc_move_login *rsp = &evt->xfer_iu->move_login;
4557848c7085STyrel Datwyler 	u32 status = be16_to_cpu(rsp->common.status);
4558848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
4559848c7085STyrel Datwyler 
4560848c7085STyrel Datwyler 	vhost->discovery_threads--;
4561848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4562848c7085STyrel Datwyler 	switch (status) {
4563848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
4564577608a2STyrel Datwyler 		tgt_dbg(tgt, "%s Move Login succeeded for new scsi_id: %llX\n",
4565577608a2STyrel Datwyler 			proto_type[tgt->protocol], tgt->new_scsi_id);
4566848c7085STyrel Datwyler 		tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name);
4567848c7085STyrel Datwyler 		tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name);
4568848c7085STyrel Datwyler 		tgt->scsi_id = tgt->new_scsi_id;
4569848c7085STyrel Datwyler 		tgt->ids.port_id = tgt->scsi_id;
4570848c7085STyrel Datwyler 		memcpy(&tgt->service_parms, &rsp->service_parms,
4571848c7085STyrel Datwyler 		       sizeof(tgt->service_parms));
4572848c7085STyrel Datwyler 		memcpy(&tgt->service_parms_change, &rsp->service_parms_change,
4573848c7085STyrel Datwyler 		       sizeof(tgt->service_parms_change));
4574848c7085STyrel Datwyler 		ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli);
4575848c7085STyrel Datwyler 		break;
4576848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
4577848c7085STyrel Datwyler 		break;
4578848c7085STyrel Datwyler 	case IBMVFC_MAD_CRQ_ERROR:
4579848c7085STyrel Datwyler 		ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_move_login);
4580848c7085STyrel Datwyler 		break;
4581848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
4582848c7085STyrel Datwyler 	default:
4583848c7085STyrel Datwyler 		level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_move_login);
4584848c7085STyrel Datwyler 
4585848c7085STyrel Datwyler 		tgt_log(tgt, level,
4586577608a2STyrel Datwyler 			"%s Move Login failed: new scsi_id: %llX, flags:%x, vios_flags:%x, rc=0x%02X\n",
4587577608a2STyrel Datwyler 			proto_type[tgt->protocol], tgt->new_scsi_id,
4588577608a2STyrel Datwyler 			be32_to_cpu(rsp->flags), be16_to_cpu(rsp->vios_flags),
4589848c7085STyrel Datwyler 			status);
4590848c7085STyrel Datwyler 		break;
4591848c7085STyrel Datwyler 	}
4592848c7085STyrel Datwyler 
4593848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4594848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4595848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4596848c7085STyrel Datwyler }
4597848c7085STyrel Datwyler 
4598848c7085STyrel Datwyler 
4599848c7085STyrel Datwyler /**
4600848c7085STyrel Datwyler  * ibmvfc_tgt_move_login - Initiate a move login for specified target
4601848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4602848c7085STyrel Datwyler  *
4603848c7085STyrel Datwyler  **/
ibmvfc_tgt_move_login(struct ibmvfc_target * tgt)4604848c7085STyrel Datwyler static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt)
4605848c7085STyrel Datwyler {
4606848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4607848c7085STyrel Datwyler 	struct ibmvfc_move_login *move;
4608848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4609848c7085STyrel Datwyler 
4610848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4611848c7085STyrel Datwyler 		return;
4612848c7085STyrel Datwyler 
4613848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4614848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4615848c7085STyrel Datwyler 	if (!evt) {
4616848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
4617848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4618848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4619848c7085STyrel Datwyler 		return;
4620848c7085STyrel Datwyler 	}
4621848c7085STyrel Datwyler 	vhost->discovery_threads++;
4622848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
4623848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_tgt_move_login_done, IBMVFC_MAD_FORMAT);
4624848c7085STyrel Datwyler 	evt->tgt = tgt;
4625848c7085STyrel Datwyler 	move = &evt->iu.move_login;
4626848c7085STyrel Datwyler 	memset(move, 0, sizeof(*move));
4627848c7085STyrel Datwyler 	move->common.version = cpu_to_be32(1);
4628577608a2STyrel Datwyler 	if (tgt->protocol == IBMVFC_PROTO_SCSI)
4629848c7085STyrel Datwyler 		move->common.opcode = cpu_to_be32(IBMVFC_MOVE_LOGIN);
4630577608a2STyrel Datwyler 	else
4631577608a2STyrel Datwyler 		move->common.opcode = cpu_to_be32(IBMVFC_NVMF_MOVE_LOGIN);
4632848c7085STyrel Datwyler 	move->common.length = cpu_to_be16(sizeof(*move));
4633848c7085STyrel Datwyler 
4634848c7085STyrel Datwyler 	move->old_scsi_id = cpu_to_be64(tgt->scsi_id);
4635848c7085STyrel Datwyler 	move->new_scsi_id = cpu_to_be64(tgt->new_scsi_id);
4636848c7085STyrel Datwyler 	move->wwpn = cpu_to_be64(tgt->wwpn);
4637848c7085STyrel Datwyler 	move->node_name = cpu_to_be64(tgt->ids.node_name);
4638848c7085STyrel Datwyler 
4639848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
4640848c7085STyrel Datwyler 		vhost->discovery_threads--;
4641848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
4642848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4643848c7085STyrel Datwyler 	} else
4644577608a2STyrel Datwyler 		tgt_dbg(tgt, "Sent %s Move Login for new scsi_id: %llX\n",
4645577608a2STyrel Datwyler 			proto_type[tgt->protocol], tgt->new_scsi_id);
4646848c7085STyrel Datwyler }
4647848c7085STyrel Datwyler 
4648848c7085STyrel Datwyler /**
4649848c7085STyrel Datwyler  * ibmvfc_adisc_needs_plogi - Does device need PLOGI?
4650848c7085STyrel Datwyler  * @mad:	ibmvfc passthru mad struct
4651848c7085STyrel Datwyler  * @tgt:	ibmvfc target struct
4652848c7085STyrel Datwyler  *
4653848c7085STyrel Datwyler  * Returns:
4654848c7085STyrel Datwyler  *	1 if PLOGI needed / 0 if PLOGI not needed
4655848c7085STyrel Datwyler  **/
ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad * mad,struct ibmvfc_target * tgt)4656848c7085STyrel Datwyler static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad,
4657848c7085STyrel Datwyler 				    struct ibmvfc_target *tgt)
4658848c7085STyrel Datwyler {
4659848c7085STyrel Datwyler 	if (wwn_to_u64((u8 *)&mad->fc_iu.response[2]) != tgt->ids.port_name)
4660848c7085STyrel Datwyler 		return 1;
4661848c7085STyrel Datwyler 	if (wwn_to_u64((u8 *)&mad->fc_iu.response[4]) != tgt->ids.node_name)
4662848c7085STyrel Datwyler 		return 1;
4663848c7085STyrel Datwyler 	if (be32_to_cpu(mad->fc_iu.response[6]) != tgt->scsi_id)
4664848c7085STyrel Datwyler 		return 1;
4665848c7085STyrel Datwyler 	return 0;
4666848c7085STyrel Datwyler }
4667848c7085STyrel Datwyler 
4668848c7085STyrel Datwyler /**
4669848c7085STyrel Datwyler  * ibmvfc_tgt_adisc_done - Completion handler for ADISC
4670848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4671848c7085STyrel Datwyler  *
4672848c7085STyrel Datwyler  **/
ibmvfc_tgt_adisc_done(struct ibmvfc_event * evt)4673848c7085STyrel Datwyler static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
4674848c7085STyrel Datwyler {
4675848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4676848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4677848c7085STyrel Datwyler 	struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
4678848c7085STyrel Datwyler 	u32 status = be16_to_cpu(mad->common.status);
4679848c7085STyrel Datwyler 	u8 fc_reason, fc_explain;
4680848c7085STyrel Datwyler 
4681848c7085STyrel Datwyler 	vhost->discovery_threads--;
4682848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4683848c7085STyrel Datwyler 	timer_delete(&tgt->timer);
4684848c7085STyrel Datwyler 
4685848c7085STyrel Datwyler 	switch (status) {
4686848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
4687848c7085STyrel Datwyler 		tgt_dbg(tgt, "ADISC succeeded\n");
4688848c7085STyrel Datwyler 		if (ibmvfc_adisc_needs_plogi(mad, tgt))
4689848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4690848c7085STyrel Datwyler 		break;
4691848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
4692848c7085STyrel Datwyler 		break;
4693848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
4694848c7085STyrel Datwyler 	default:
4695848c7085STyrel Datwyler 		ibmvfc_del_tgt(tgt);
4696848c7085STyrel Datwyler 		fc_reason = (be32_to_cpu(mad->fc_iu.response[1]) & 0x00ff0000) >> 16;
4697848c7085STyrel Datwyler 		fc_explain = (be32_to_cpu(mad->fc_iu.response[1]) & 0x0000ff00) >> 8;
4698848c7085STyrel Datwyler 		tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
4699848c7085STyrel Datwyler 			 ibmvfc_get_cmd_error(be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error)),
4700848c7085STyrel Datwyler 			 be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error),
4701848c7085STyrel Datwyler 			 ibmvfc_get_fc_type(fc_reason), fc_reason,
4702848c7085STyrel Datwyler 			 ibmvfc_get_ls_explain(fc_explain), fc_explain, status);
4703848c7085STyrel Datwyler 		break;
4704848c7085STyrel Datwyler 	}
4705848c7085STyrel Datwyler 
4706848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4707848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4708848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4709848c7085STyrel Datwyler }
4710848c7085STyrel Datwyler 
4711848c7085STyrel Datwyler /**
4712848c7085STyrel Datwyler  * ibmvfc_init_passthru - Initialize an event struct for FC passthru
4713848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
4714848c7085STyrel Datwyler  *
4715848c7085STyrel Datwyler  **/
ibmvfc_init_passthru(struct ibmvfc_event * evt)4716848c7085STyrel Datwyler static void ibmvfc_init_passthru(struct ibmvfc_event *evt)
4717848c7085STyrel Datwyler {
4718848c7085STyrel Datwyler 	struct ibmvfc_passthru_mad *mad = &evt->iu.passthru;
4719848c7085STyrel Datwyler 
4720848c7085STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
4721848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
4722848c7085STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_PASSTHRU);
4723848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu));
4724848c7085STyrel Datwyler 	mad->cmd_ioba.va = cpu_to_be64((u64)be64_to_cpu(evt->crq.ioba) +
4725848c7085STyrel Datwyler 		offsetof(struct ibmvfc_passthru_mad, iu));
4726848c7085STyrel Datwyler 	mad->cmd_ioba.len = cpu_to_be32(sizeof(mad->iu));
4727848c7085STyrel Datwyler 	mad->iu.cmd_len = cpu_to_be32(sizeof(mad->fc_iu.payload));
4728848c7085STyrel Datwyler 	mad->iu.rsp_len = cpu_to_be32(sizeof(mad->fc_iu.response));
4729848c7085STyrel Datwyler 	mad->iu.cmd.va = cpu_to_be64((u64)be64_to_cpu(evt->crq.ioba) +
4730848c7085STyrel Datwyler 		offsetof(struct ibmvfc_passthru_mad, fc_iu) +
4731848c7085STyrel Datwyler 		offsetof(struct ibmvfc_passthru_fc_iu, payload));
4732848c7085STyrel Datwyler 	mad->iu.cmd.len = cpu_to_be32(sizeof(mad->fc_iu.payload));
4733848c7085STyrel Datwyler 	mad->iu.rsp.va = cpu_to_be64((u64)be64_to_cpu(evt->crq.ioba) +
4734848c7085STyrel Datwyler 		offsetof(struct ibmvfc_passthru_mad, fc_iu) +
4735848c7085STyrel Datwyler 		offsetof(struct ibmvfc_passthru_fc_iu, response));
4736848c7085STyrel Datwyler 	mad->iu.rsp.len = cpu_to_be32(sizeof(mad->fc_iu.response));
4737848c7085STyrel Datwyler }
4738848c7085STyrel Datwyler 
4739848c7085STyrel Datwyler /**
4740848c7085STyrel Datwyler  * ibmvfc_tgt_adisc_cancel_done - Completion handler when cancelling an ADISC
4741848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
4742848c7085STyrel Datwyler  *
4743848c7085STyrel Datwyler  * Just cleanup this event struct. Everything else is handled by
4744848c7085STyrel Datwyler  * the ADISC completion handler. If the ADISC never actually comes
4745848c7085STyrel Datwyler  * back, we still have the timer running on the ADISC event struct
4746848c7085STyrel Datwyler  * which will fire and cause the CRQ to get reset.
4747848c7085STyrel Datwyler  *
4748848c7085STyrel Datwyler  **/
ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event * evt)4749848c7085STyrel Datwyler static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt)
4750848c7085STyrel Datwyler {
4751848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4752848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4753848c7085STyrel Datwyler 
4754848c7085STyrel Datwyler 	tgt_dbg(tgt, "ADISC cancel complete\n");
4755848c7085STyrel Datwyler 	vhost->abort_threads--;
4756848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4757848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4758848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4759848c7085STyrel Datwyler }
4760848c7085STyrel Datwyler 
4761848c7085STyrel Datwyler /**
4762848c7085STyrel Datwyler  * ibmvfc_adisc_timeout - Handle an ADISC timeout
4763848c7085STyrel Datwyler  * @t:		ibmvfc target struct
4764848c7085STyrel Datwyler  *
4765848c7085STyrel Datwyler  * If an ADISC times out, send a cancel. If the cancel times
4766848c7085STyrel Datwyler  * out, reset the CRQ. When the ADISC comes back as cancelled,
4767848c7085STyrel Datwyler  * log back into the target.
4768848c7085STyrel Datwyler  **/
ibmvfc_adisc_timeout(struct timer_list * t)4769848c7085STyrel Datwyler static void ibmvfc_adisc_timeout(struct timer_list *t)
4770848c7085STyrel Datwyler {
4771848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = timer_container_of(tgt, t, timer);
4772848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4773848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4774848c7085STyrel Datwyler 	struct ibmvfc_tmf *tmf;
4775848c7085STyrel Datwyler 	unsigned long flags;
4776848c7085STyrel Datwyler 	int rc;
4777848c7085STyrel Datwyler 
4778848c7085STyrel Datwyler 	tgt_dbg(tgt, "ADISC timeout\n");
4779848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
4780848c7085STyrel Datwyler 	if (vhost->abort_threads >= disc_threads ||
4781848c7085STyrel Datwyler 	    tgt->action != IBMVFC_TGT_ACTION_INIT_WAIT ||
4782848c7085STyrel Datwyler 	    vhost->state != IBMVFC_INITIALIZING ||
4783848c7085STyrel Datwyler 	    vhost->action != IBMVFC_HOST_ACTION_QUERY_TGTS) {
4784848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
4785848c7085STyrel Datwyler 		return;
4786848c7085STyrel Datwyler 	}
4787848c7085STyrel Datwyler 
4788848c7085STyrel Datwyler 	vhost->abort_threads++;
4789848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4790848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4791848c7085STyrel Datwyler 	if (!evt) {
4792848c7085STyrel Datwyler 		tgt_err(tgt, "Failed to get cancel event for ADISC.\n");
4793848c7085STyrel Datwyler 		vhost->abort_threads--;
4794848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4795848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4796848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
4797848c7085STyrel Datwyler 		return;
4798848c7085STyrel Datwyler 	}
4799848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT);
4800848c7085STyrel Datwyler 
4801848c7085STyrel Datwyler 	evt->tgt = tgt;
4802848c7085STyrel Datwyler 	tmf = &evt->iu.tmf;
4803848c7085STyrel Datwyler 	memset(tmf, 0, sizeof(*tmf));
4804848c7085STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) {
4805848c7085STyrel Datwyler 		tmf->common.version = cpu_to_be32(2);
4806848c7085STyrel Datwyler 		tmf->target_wwpn = cpu_to_be64(tgt->wwpn);
4807848c7085STyrel Datwyler 	} else {
4808848c7085STyrel Datwyler 		tmf->common.version = cpu_to_be32(1);
4809848c7085STyrel Datwyler 	}
4810848c7085STyrel Datwyler 	tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD);
4811848c7085STyrel Datwyler 	tmf->common.length = cpu_to_be16(sizeof(*tmf));
4812848c7085STyrel Datwyler 	tmf->scsi_id = cpu_to_be64(tgt->scsi_id);
4813848c7085STyrel Datwyler 	tmf->cancel_key = cpu_to_be32(tgt->cancel_key);
4814848c7085STyrel Datwyler 
4815848c7085STyrel Datwyler 	rc = ibmvfc_send_event(evt, vhost, default_timeout);
4816848c7085STyrel Datwyler 
4817848c7085STyrel Datwyler 	if (rc) {
4818848c7085STyrel Datwyler 		tgt_err(tgt, "Failed to send cancel event for ADISC. rc=%d\n", rc);
4819848c7085STyrel Datwyler 		vhost->abort_threads--;
4820848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4821848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4822848c7085STyrel Datwyler 	} else
4823848c7085STyrel Datwyler 		tgt_dbg(tgt, "Attempting to cancel ADISC\n");
4824848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
4825848c7085STyrel Datwyler }
4826848c7085STyrel Datwyler 
4827848c7085STyrel Datwyler /**
4828848c7085STyrel Datwyler  * ibmvfc_tgt_adisc - Initiate an ADISC for specified target
4829848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
4830848c7085STyrel Datwyler  *
4831848c7085STyrel Datwyler  * When sending an ADISC we end up with two timers running. The
4832848c7085STyrel Datwyler  * first timer is the timer in the ibmvfc target struct. If this
4833848c7085STyrel Datwyler  * fires, we send a cancel to the target. The second timer is the
4834848c7085STyrel Datwyler  * timer on the ibmvfc event for the ADISC, which is longer. If that
4835848c7085STyrel Datwyler  * fires, it means the ADISC timed out and our attempt to cancel it
4836848c7085STyrel Datwyler  * also failed, so we need to reset the CRQ.
4837848c7085STyrel Datwyler  **/
ibmvfc_tgt_adisc(struct ibmvfc_target * tgt)4838848c7085STyrel Datwyler static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
4839848c7085STyrel Datwyler {
4840848c7085STyrel Datwyler 	struct ibmvfc_passthru_mad *mad;
4841848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4842848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4843848c7085STyrel Datwyler 
4844848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4845848c7085STyrel Datwyler 		return;
4846848c7085STyrel Datwyler 
4847848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4848848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4849848c7085STyrel Datwyler 	if (!evt) {
4850848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4851848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4852848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4853848c7085STyrel Datwyler 		return;
4854848c7085STyrel Datwyler 	}
4855848c7085STyrel Datwyler 	vhost->discovery_threads++;
4856848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT);
4857848c7085STyrel Datwyler 	evt->tgt = tgt;
4858848c7085STyrel Datwyler 
4859848c7085STyrel Datwyler 	ibmvfc_init_passthru(evt);
4860848c7085STyrel Datwyler 	mad = &evt->iu.passthru;
4861848c7085STyrel Datwyler 	mad->iu.flags = cpu_to_be32(IBMVFC_FC_ELS);
4862848c7085STyrel Datwyler 	mad->iu.scsi_id = cpu_to_be64(tgt->scsi_id);
4863848c7085STyrel Datwyler 	mad->iu.cancel_key = cpu_to_be32(tgt->cancel_key);
4864848c7085STyrel Datwyler 
4865848c7085STyrel Datwyler 	mad->fc_iu.payload[0] = cpu_to_be32(IBMVFC_ADISC);
4866848c7085STyrel Datwyler 	memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name,
4867848c7085STyrel Datwyler 	       sizeof(vhost->login_buf->resp.port_name));
4868848c7085STyrel Datwyler 	memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name,
4869848c7085STyrel Datwyler 	       sizeof(vhost->login_buf->resp.node_name));
4870848c7085STyrel Datwyler 	mad->fc_iu.payload[6] = cpu_to_be32(be64_to_cpu(vhost->login_buf->resp.scsi_id) & 0x00ffffff);
4871848c7085STyrel Datwyler 
4872848c7085STyrel Datwyler 	if (timer_pending(&tgt->timer))
4873848c7085STyrel Datwyler 		mod_timer(&tgt->timer, jiffies + (IBMVFC_ADISC_TIMEOUT * HZ));
4874848c7085STyrel Datwyler 	else {
4875848c7085STyrel Datwyler 		tgt->timer.expires = jiffies + (IBMVFC_ADISC_TIMEOUT * HZ);
4876848c7085STyrel Datwyler 		add_timer(&tgt->timer);
4877848c7085STyrel Datwyler 	}
4878848c7085STyrel Datwyler 
4879848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
4880848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT)) {
4881848c7085STyrel Datwyler 		vhost->discovery_threads--;
4882848c7085STyrel Datwyler 		timer_delete(&tgt->timer);
4883848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4884848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4885848c7085STyrel Datwyler 	} else
4886848c7085STyrel Datwyler 		tgt_dbg(tgt, "Sent ADISC\n");
4887848c7085STyrel Datwyler }
4888848c7085STyrel Datwyler 
4889848c7085STyrel Datwyler /**
4890848c7085STyrel Datwyler  * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
4891848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
4892848c7085STyrel Datwyler  *
4893848c7085STyrel Datwyler  **/
ibmvfc_tgt_query_target_done(struct ibmvfc_event * evt)4894848c7085STyrel Datwyler static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
4895848c7085STyrel Datwyler {
4896848c7085STyrel Datwyler 	struct ibmvfc_target *tgt = evt->tgt;
4897848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
4898848c7085STyrel Datwyler 	struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt;
4899848c7085STyrel Datwyler 	u32 status = be16_to_cpu(rsp->common.status);
4900848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
4901848c7085STyrel Datwyler 
4902848c7085STyrel Datwyler 	vhost->discovery_threads--;
4903848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4904848c7085STyrel Datwyler 	switch (status) {
4905848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
49065bdeab3cSTyrel Datwyler 		tgt_dbg(tgt, "%s Query Target succeeded\n", proto_type[tgt->protocol]);
4907848c7085STyrel Datwyler 		if (be64_to_cpu(rsp->scsi_id) != tgt->scsi_id)
4908848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4909848c7085STyrel Datwyler 		else
4910848c7085STyrel Datwyler 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc);
4911848c7085STyrel Datwyler 		break;
4912848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
4913848c7085STyrel Datwyler 		break;
4914848c7085STyrel Datwyler 	case IBMVFC_MAD_CRQ_ERROR:
4915848c7085STyrel Datwyler 		ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
4916848c7085STyrel Datwyler 		break;
4917848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
4918848c7085STyrel Datwyler 	default:
4919848c7085STyrel Datwyler 		if ((be16_to_cpu(rsp->status) & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED &&
4920848c7085STyrel Datwyler 		    be16_to_cpu(rsp->error) == IBMVFC_UNABLE_TO_PERFORM_REQ &&
4921848c7085STyrel Datwyler 		    be16_to_cpu(rsp->fc_explain) == IBMVFC_PORT_NAME_NOT_REG)
4922848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4923848c7085STyrel Datwyler 		else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
4924848c7085STyrel Datwyler 			level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
4925848c7085STyrel Datwyler 		else
4926848c7085STyrel Datwyler 			ibmvfc_del_tgt(tgt);
4927848c7085STyrel Datwyler 
49285bdeab3cSTyrel Datwyler 		tgt_log(tgt, level, "%s Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
49295bdeab3cSTyrel Datwyler 			proto_type[tgt->protocol], ibmvfc_get_cmd_error(be16_to_cpu(rsp->status),
49305bdeab3cSTyrel Datwyler 			be16_to_cpu(rsp->error)), be16_to_cpu(rsp->status), be16_to_cpu(rsp->error),
4931848c7085STyrel Datwyler 			ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), be16_to_cpu(rsp->fc_type),
4932848c7085STyrel Datwyler 			ibmvfc_get_gs_explain(be16_to_cpu(rsp->fc_explain)), be16_to_cpu(rsp->fc_explain),
4933848c7085STyrel Datwyler 			status);
4934848c7085STyrel Datwyler 		break;
4935848c7085STyrel Datwyler 	}
4936848c7085STyrel Datwyler 
4937848c7085STyrel Datwyler 	kref_put(&tgt->kref, ibmvfc_release_tgt);
4938848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
4939848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
4940848c7085STyrel Datwyler }
4941848c7085STyrel Datwyler 
4942848c7085STyrel Datwyler /**
4943848c7085STyrel Datwyler  * ibmvfc_tgt_query_target - Initiate a Query Target for specified target
4944848c7085STyrel Datwyler  * @tgt:	ibmvfc target struct
4945848c7085STyrel Datwyler  *
4946848c7085STyrel Datwyler  **/
ibmvfc_tgt_query_target(struct ibmvfc_target * tgt)4947848c7085STyrel Datwyler static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt)
4948848c7085STyrel Datwyler {
4949848c7085STyrel Datwyler 	struct ibmvfc_query_tgt *query_tgt;
4950848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
4951848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
4952848c7085STyrel Datwyler 
4953848c7085STyrel Datwyler 	if (vhost->discovery_threads >= disc_threads)
4954848c7085STyrel Datwyler 		return;
4955848c7085STyrel Datwyler 
4956848c7085STyrel Datwyler 	kref_get(&tgt->kref);
4957848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
4958848c7085STyrel Datwyler 	if (!evt) {
4959848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4960848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4961848c7085STyrel Datwyler 		__ibmvfc_reset_host(vhost);
4962848c7085STyrel Datwyler 		return;
4963848c7085STyrel Datwyler 	}
4964848c7085STyrel Datwyler 	vhost->discovery_threads++;
4965848c7085STyrel Datwyler 	evt->tgt = tgt;
4966848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT);
4967848c7085STyrel Datwyler 	query_tgt = &evt->iu.query_tgt;
4968848c7085STyrel Datwyler 	memset(query_tgt, 0, sizeof(*query_tgt));
4969848c7085STyrel Datwyler 	query_tgt->common.version = cpu_to_be32(1);
49705bdeab3cSTyrel Datwyler 	if (tgt->protocol == IBMVFC_PROTO_SCSI)
4971848c7085STyrel Datwyler 		query_tgt->common.opcode = cpu_to_be32(IBMVFC_QUERY_TARGET);
49725bdeab3cSTyrel Datwyler 	else
49735bdeab3cSTyrel Datwyler 		query_tgt->common.opcode = cpu_to_be32(IBMVFC_NVMF_QUERY_TARGET);
4974848c7085STyrel Datwyler 	query_tgt->common.length = cpu_to_be16(sizeof(*query_tgt));
4975848c7085STyrel Datwyler 	query_tgt->wwpn = cpu_to_be64(tgt->ids.port_name);
4976848c7085STyrel Datwyler 
4977848c7085STyrel Datwyler 	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
4978848c7085STyrel Datwyler 	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
4979848c7085STyrel Datwyler 		vhost->discovery_threads--;
4980848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4981848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
4982848c7085STyrel Datwyler 	} else
49835bdeab3cSTyrel Datwyler 		tgt_dbg(tgt, "Sent %s Query Target\n", proto_type[tgt->protocol]);
4984848c7085STyrel Datwyler }
4985848c7085STyrel Datwyler 
4986848c7085STyrel Datwyler /**
4987848c7085STyrel Datwyler  * ibmvfc_alloc_target - Allocate and initialize an ibmvfc target
4988848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
4989848c7085STyrel Datwyler  * @target:		Holds SCSI ID to allocate target forand the WWPN
4990848c7085STyrel Datwyler  *
4991848c7085STyrel Datwyler  * Returns:
4992848c7085STyrel Datwyler  *	0 on success / other on failure
4993848c7085STyrel Datwyler  **/
ibmvfc_alloc_target(struct ibmvfc_host * vhost,struct ibmvfc_discover_targets_entry * target,enum ibmvfc_protocol protocol)4994848c7085STyrel Datwyler static int ibmvfc_alloc_target(struct ibmvfc_host *vhost,
4995249313b3STyrel Datwyler 			       struct ibmvfc_discover_targets_entry *target,
4996249313b3STyrel Datwyler 			       enum ibmvfc_protocol protocol)
4997848c7085STyrel Datwyler {
4998848c7085STyrel Datwyler 	struct ibmvfc_target *stgt = NULL;
4999848c7085STyrel Datwyler 	struct ibmvfc_target *wtgt = NULL;
5000848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
5001249313b3STyrel Datwyler 	struct ibmvfc_channels *channels;
5002848c7085STyrel Datwyler 	unsigned long flags;
5003848c7085STyrel Datwyler 	u64 scsi_id = be32_to_cpu(target->scsi_id) & IBMVFC_DISC_TGT_SCSI_ID_MASK;
5004848c7085STyrel Datwyler 	u64 wwpn = be64_to_cpu(target->wwpn);
5005848c7085STyrel Datwyler 
5006249313b3STyrel Datwyler 	if (protocol == IBMVFC_PROTO_SCSI)
5007249313b3STyrel Datwyler 		channels = &vhost->scsi_scrqs;
5008249313b3STyrel Datwyler 	else
5009249313b3STyrel Datwyler 		channels = &vhost->nvme_scrqs;
5010249313b3STyrel Datwyler 
5011848c7085STyrel Datwyler 	/* Look to see if we already have a target allocated for this SCSI ID or WWPN */
5012848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
5013249313b3STyrel Datwyler 	list_for_each_entry(tgt, &channels->targets, queue) {
5014848c7085STyrel Datwyler 		if (tgt->wwpn == wwpn) {
5015848c7085STyrel Datwyler 			wtgt = tgt;
5016848c7085STyrel Datwyler 			break;
5017848c7085STyrel Datwyler 		}
5018848c7085STyrel Datwyler 	}
5019848c7085STyrel Datwyler 
5020249313b3STyrel Datwyler 	list_for_each_entry(tgt, &channels->targets, queue) {
5021848c7085STyrel Datwyler 		if (tgt->scsi_id == scsi_id) {
5022848c7085STyrel Datwyler 			stgt = tgt;
5023848c7085STyrel Datwyler 			break;
5024848c7085STyrel Datwyler 		}
5025848c7085STyrel Datwyler 	}
5026848c7085STyrel Datwyler 
5027848c7085STyrel Datwyler 	if (wtgt && !stgt) {
5028848c7085STyrel Datwyler 		/*
5029848c7085STyrel Datwyler 		 * A WWPN target has moved and we still are tracking the old
5030848c7085STyrel Datwyler 		 * SCSI ID.  The only way we should be able to get here is if
5031848c7085STyrel Datwyler 		 * we attempted to send an implicit logout for the old SCSI ID
5032848c7085STyrel Datwyler 		 * and it failed for some reason, such as there being I/O
5033848c7085STyrel Datwyler 		 * pending to the target. In this case, we will have already
5034848c7085STyrel Datwyler 		 * deleted the rport from the FC transport so we do a move
5035848c7085STyrel Datwyler 		 * login, which works even with I/O pending, however, if
5036848c7085STyrel Datwyler 		 * there is still I/O pending, it will stay outstanding, so
5037848c7085STyrel Datwyler 		 * we only do this if fast fail is disabled for the rport,
5038848c7085STyrel Datwyler 		 * otherwise we let terminate_rport_io clean up the port
5039848c7085STyrel Datwyler 		 * before we login at the new location.
5040848c7085STyrel Datwyler 		 */
5041848c7085STyrel Datwyler 		if (wtgt->action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) {
5042848c7085STyrel Datwyler 			if (wtgt->move_login) {
5043848c7085STyrel Datwyler 				/*
5044848c7085STyrel Datwyler 				 * Do a move login here. The old target is no longer
5045848c7085STyrel Datwyler 				 * known to the transport layer We don't use the
5046848c7085STyrel Datwyler 				 * normal ibmvfc_set_tgt_action to set this, as we
5047848c7085STyrel Datwyler 				 * don't normally want to allow this state change.
5048848c7085STyrel Datwyler 				 */
5049848c7085STyrel Datwyler 				wtgt->new_scsi_id = scsi_id;
5050848c7085STyrel Datwyler 				wtgt->action = IBMVFC_TGT_ACTION_INIT;
5051848c7085STyrel Datwyler 				wtgt->init_retries = 0;
5052848c7085STyrel Datwyler 				ibmvfc_init_tgt(wtgt, ibmvfc_tgt_move_login);
5053848c7085STyrel Datwyler 			}
5054848c7085STyrel Datwyler 			goto unlock_out;
5055848c7085STyrel Datwyler 		} else {
5056848c7085STyrel Datwyler 			tgt_err(wtgt, "Unexpected target state: %d, %p\n",
5057848c7085STyrel Datwyler 				wtgt->action, wtgt->rport);
5058848c7085STyrel Datwyler 		}
5059848c7085STyrel Datwyler 	} else if (stgt) {
5060848c7085STyrel Datwyler 		if (tgt->need_login)
5061848c7085STyrel Datwyler 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
5062848c7085STyrel Datwyler 		goto unlock_out;
5063848c7085STyrel Datwyler 	}
5064848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
5065848c7085STyrel Datwyler 
5066848c7085STyrel Datwyler 	tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO);
5067848c7085STyrel Datwyler 	memset(tgt, 0, sizeof(*tgt));
5068249313b3STyrel Datwyler 	tgt->protocol = protocol;
5069848c7085STyrel Datwyler 	tgt->scsi_id = scsi_id;
5070848c7085STyrel Datwyler 	tgt->wwpn = wwpn;
5071848c7085STyrel Datwyler 	tgt->vhost = vhost;
5072848c7085STyrel Datwyler 	tgt->need_login = 1;
5073848c7085STyrel Datwyler 	timer_setup(&tgt->timer, ibmvfc_adisc_timeout, 0);
5074848c7085STyrel Datwyler 	kref_init(&tgt->kref);
5075848c7085STyrel Datwyler 	ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
5076848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
5077848c7085STyrel Datwyler 	tgt->cancel_key = vhost->task_set++;
5078249313b3STyrel Datwyler 	list_add_tail(&tgt->queue, &channels->targets);
5079848c7085STyrel Datwyler 
5080848c7085STyrel Datwyler unlock_out:
5081848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
5082848c7085STyrel Datwyler 	return 0;
5083848c7085STyrel Datwyler }
5084848c7085STyrel Datwyler 
5085848c7085STyrel Datwyler /**
5086848c7085STyrel Datwyler  * ibmvfc_alloc_targets - Allocate and initialize ibmvfc targets
5087848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5088848c7085STyrel Datwyler  *
5089848c7085STyrel Datwyler  * Returns:
5090848c7085STyrel Datwyler  *	0 on success / other on failure
5091848c7085STyrel Datwyler  **/
ibmvfc_alloc_targets(struct ibmvfc_host * vhost)5092848c7085STyrel Datwyler static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost)
5093848c7085STyrel Datwyler {
5094848c7085STyrel Datwyler 	int i, rc;
5095848c7085STyrel Datwyler 
5096848c7085STyrel Datwyler 	for (i = 0, rc = 0; !rc && i < vhost->scsi_scrqs.num_targets; i++)
5097249313b3STyrel Datwyler 		rc = ibmvfc_alloc_target(vhost, &vhost->scsi_scrqs.disc_buf[i],
5098249313b3STyrel Datwyler 					 vhost->scsi_scrqs.protocol);
5099249313b3STyrel Datwyler 	for (i = 0; !rc && i < vhost->nvme_scrqs.num_targets; i++)
5100249313b3STyrel Datwyler 		rc = ibmvfc_alloc_target(vhost, &vhost->nvme_scrqs.disc_buf[i],
5101249313b3STyrel Datwyler 					 vhost->nvme_scrqs.protocol);
5102848c7085STyrel Datwyler 
5103848c7085STyrel Datwyler 	return rc;
5104848c7085STyrel Datwyler }
5105848c7085STyrel Datwyler 
5106848c7085STyrel Datwyler /**
5107848c7085STyrel Datwyler  * ibmvfc_discover_targets_done - Completion handler for discover targets MAD
5108848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
5109848c7085STyrel Datwyler  *
5110848c7085STyrel Datwyler  **/
ibmvfc_discover_targets_done(struct ibmvfc_event * evt)5111848c7085STyrel Datwyler static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
5112848c7085STyrel Datwyler {
5113848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5114848c7085STyrel Datwyler 	struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets;
51155e9dd037STyrel Datwyler 	struct ibmvfc_channels *channels;
5116848c7085STyrel Datwyler 	u32 mad_status = be16_to_cpu(rsp->common.status);
51175e9dd037STyrel Datwyler 	u32 opcode = be32_to_cpu(rsp->common.opcode);
5118848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5119848c7085STyrel Datwyler 
51205e9dd037STyrel Datwyler 	if (opcode == IBMVFC_DISC_TARGETS)
51215e9dd037STyrel Datwyler 		channels = &vhost->scsi_scrqs;
51225e9dd037STyrel Datwyler 	else
51235e9dd037STyrel Datwyler 		channels = &vhost->nvme_scrqs;
51245e9dd037STyrel Datwyler 
5125848c7085STyrel Datwyler 	switch (mad_status) {
5126848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
51275e9dd037STyrel Datwyler 		ibmvfc_dbg(vhost, "Discover %s Targets succeeded\n",
51285e9dd037STyrel Datwyler 			   proto_type[channels->protocol]);
51295e9dd037STyrel Datwyler 		channels->num_targets = min_t(u32, be32_to_cpu(rsp->num_written),
5130848c7085STyrel Datwyler 					      max_targets);
51315e9dd037STyrel Datwyler 		ibmvfc_dbg(vhost, "%d %s targets found\n", channels->num_targets,
51325e9dd037STyrel Datwyler 			   proto_type[channels->protocol]);
5133848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
5134848c7085STyrel Datwyler 		break;
5135848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5136848c7085STyrel Datwyler 		level += ibmvfc_retry_host_init(vhost);
51375e9dd037STyrel Datwyler 		ibmvfc_log(vhost, level, "Discover %s Targets failed: %s (%x:%x)\n",
51385e9dd037STyrel Datwyler 			   proto_type[channels->protocol],
5139848c7085STyrel Datwyler 			   ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
5140848c7085STyrel Datwyler 			   be16_to_cpu(rsp->status), be16_to_cpu(rsp->error));
5141848c7085STyrel Datwyler 		break;
5142848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5143848c7085STyrel Datwyler 		break;
5144848c7085STyrel Datwyler 	default:
5145848c7085STyrel Datwyler 		dev_err(vhost->dev, "Invalid Discover Targets response: 0x%x\n", mad_status);
5146848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5147848c7085STyrel Datwyler 		break;
5148848c7085STyrel Datwyler 	}
5149848c7085STyrel Datwyler 
5150848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
5151848c7085STyrel Datwyler 	wake_up(&vhost->work_wait_q);
5152848c7085STyrel Datwyler }
5153848c7085STyrel Datwyler 
ibmvfc_get_disc_event(struct ibmvfc_channels * channels)5154a29ee147STyrel Datwyler static struct ibmvfc_event *ibmvfc_get_disc_event(struct ibmvfc_channels *channels)
5155a29ee147STyrel Datwyler {
5156a29ee147STyrel Datwyler 	struct ibmvfc_discover_targets *mad;
5157a29ee147STyrel Datwyler 	struct ibmvfc_host *vhost = ibmvfc_channels_to_vhost(channels);
5158a29ee147STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
5159a29ee147STyrel Datwyler 
5160a29ee147STyrel Datwyler 	if (!evt)
5161a29ee147STyrel Datwyler 		return NULL;
5162a29ee147STyrel Datwyler 
5163a29ee147STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT);
5164a29ee147STyrel Datwyler 	mad = &evt->iu.discover_targets;
5165a29ee147STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
5166a29ee147STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5167a29ee147STyrel Datwyler 	if (channels->protocol == IBMVFC_PROTO_SCSI)
5168a29ee147STyrel Datwyler 		mad->common.opcode = cpu_to_be32(IBMVFC_DISC_TARGETS);
5169a29ee147STyrel Datwyler 	else
5170a29ee147STyrel Datwyler 		mad->common.opcode = cpu_to_be32(IBMVFC_DISC_NVMF_TARGETS);
5171a29ee147STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad));
5172a29ee147STyrel Datwyler 	mad->bufflen = cpu_to_be32(channels->disc_buf_sz);
5173a29ee147STyrel Datwyler 	mad->buffer.va = cpu_to_be64(channels->disc_buf_dma);
5174a29ee147STyrel Datwyler 	mad->buffer.len = cpu_to_be32(channels->disc_buf_sz);
5175a29ee147STyrel Datwyler 	mad->flags = cpu_to_be32(IBMVFC_DISC_TGT_PORT_ID_WWPN_LIST);
5176a29ee147STyrel Datwyler 
5177a29ee147STyrel Datwyler 	return evt;
5178a29ee147STyrel Datwyler }
5179a29ee147STyrel Datwyler 
5180848c7085STyrel Datwyler /**
5181848c7085STyrel Datwyler  * ibmvfc_discover_targets - Send Discover Targets MAD
5182848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
5183848c7085STyrel Datwyler  *
5184848c7085STyrel Datwyler  **/
ibmvfc_discover_targets(struct ibmvfc_host * vhost)5185848c7085STyrel Datwyler static void ibmvfc_discover_targets(struct ibmvfc_host *vhost)
5186848c7085STyrel Datwyler {
5187a29ee147STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_disc_event(&vhost->scsi_scrqs);
5188848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5189848c7085STyrel Datwyler 
5190848c7085STyrel Datwyler 	if (!evt) {
51915e9dd037STyrel Datwyler 		ibmvfc_log(vhost, level, "Discover SCSI Targets failed: no available events\n");
5192848c7085STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
5193848c7085STyrel Datwyler 		return;
5194848c7085STyrel Datwyler 	}
5195848c7085STyrel Datwyler 
5196848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
5197848c7085STyrel Datwyler 
5198848c7085STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
51995e9dd037STyrel Datwyler 		ibmvfc_dbg(vhost, "Sent discover SCSI targets\n");
5200848c7085STyrel Datwyler 	else
52015e9dd037STyrel Datwyler 		goto link_down;
52025e9dd037STyrel Datwyler 
52035e9dd037STyrel Datwyler 	if (!ibmvfc_nvme_active(vhost))
52045e9dd037STyrel Datwyler 		return;
52055e9dd037STyrel Datwyler 
52065e9dd037STyrel Datwyler 	evt = ibmvfc_get_disc_event(&vhost->nvme_scrqs);
52075e9dd037STyrel Datwyler 	if (!evt) {
52085e9dd037STyrel Datwyler 		ibmvfc_log(vhost, level, "Discover NVMe Targets failed: no available events\n");
52095e9dd037STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
52105e9dd037STyrel Datwyler 		return;
52115e9dd037STyrel Datwyler 	}
52125e9dd037STyrel Datwyler 
52135e9dd037STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
52145e9dd037STyrel Datwyler 		ibmvfc_dbg(vhost, "Sent discover NVMe targets\n");
52155e9dd037STyrel Datwyler 	else
52165e9dd037STyrel Datwyler 		goto link_down;
52175e9dd037STyrel Datwyler 
52185e9dd037STyrel Datwyler 	return;
52195e9dd037STyrel Datwyler 
52205e9dd037STyrel Datwyler link_down:
5221848c7085STyrel Datwyler 	ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5222848c7085STyrel Datwyler }
5223848c7085STyrel Datwyler 
ibmvfc_fabric_login_nvme_done(struct ibmvfc_event * evt)5224ecc03d95STyrel Datwyler static void ibmvfc_fabric_login_nvme_done(struct ibmvfc_event *evt)
5225ecc03d95STyrel Datwyler {
5226ecc03d95STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5227ecc03d95STyrel Datwyler 	struct ibmvfc_fabric_login_mad *rsp = &evt->xfer_iu->fabric_login;
5228ecc03d95STyrel Datwyler 	u32 mad_status = be16_to_cpu(rsp->common.status);
5229ecc03d95STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5230ecc03d95STyrel Datwyler 
5231ecc03d95STyrel Datwyler 	switch (mad_status) {
5232ecc03d95STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
52333831863fSTyrel Datwyler 		fc_host_port_id(vhost->host) = be64_to_cpu(rsp->nport_id);
52343831863fSTyrel Datwyler 		ibmvfc_nvme_register(vhost);
5235ecc03d95STyrel Datwyler 		ibmvfc_dbg(vhost, "NVMe fabric login succeeded\n");
5236ecc03d95STyrel Datwyler 		break;
5237ecc03d95STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5238ecc03d95STyrel Datwyler 		if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
5239ecc03d95STyrel Datwyler 			level += ibmvfc_retry_host_init(vhost);
5240ecc03d95STyrel Datwyler 		else
5241ecc03d95STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5242ecc03d95STyrel Datwyler 		ibmvfc_log(vhost, level, "NVMe fabric login failed: %s (%x:%x)\n",
5243ecc03d95STyrel Datwyler 			   ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
5244ecc03d95STyrel Datwyler 			   be16_to_cpu(rsp->status), be16_to_cpu(rsp->error));
5245ecc03d95STyrel Datwyler 		ibmvfc_free_event(evt);
5246ecc03d95STyrel Datwyler 		return;
5247ecc03d95STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5248ecc03d95STyrel Datwyler 		ibmvfc_free_event(evt);
5249ecc03d95STyrel Datwyler 		return;
5250ecc03d95STyrel Datwyler 	default:
5251ecc03d95STyrel Datwyler 		dev_err(vhost->dev, "Invalid NVMe fabric login response: 0x%x\n", mad_status);
5252ecc03d95STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5253ecc03d95STyrel Datwyler 		break;
5254ecc03d95STyrel Datwyler 	}
5255ecc03d95STyrel Datwyler 
5256ecc03d95STyrel Datwyler 	ibmvfc_free_event(evt);
5257ecc03d95STyrel Datwyler 
5258ecc03d95STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
5259ecc03d95STyrel Datwyler 	wake_up(&vhost->work_wait_q);
5260ecc03d95STyrel Datwyler }
5261ecc03d95STyrel Datwyler 
ibmvfc_fabric_login_nvme(struct ibmvfc_host * vhost)5262ecc03d95STyrel Datwyler static void ibmvfc_fabric_login_nvme(struct ibmvfc_host *vhost)
5263ecc03d95STyrel Datwyler {
5264ecc03d95STyrel Datwyler 	struct ibmvfc_fabric_login_mad *mad;
5265ecc03d95STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
5266ecc03d95STyrel Datwyler 
5267ecc03d95STyrel Datwyler 	if (!evt) {
5268ecc03d95STyrel Datwyler 		ibmvfc_retry_host_init(vhost);
5269ecc03d95STyrel Datwyler 		return;
5270ecc03d95STyrel Datwyler 	}
5271ecc03d95STyrel Datwyler 
5272ecc03d95STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_fabric_login_nvme_done, IBMVFC_MAD_FORMAT);
5273ecc03d95STyrel Datwyler 	mad = &evt->iu.fabric_login;
5274ecc03d95STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
5275ecc03d95STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5276ecc03d95STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_NVMF_FABRIC_LOGIN);
5277ecc03d95STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad));
5278ecc03d95STyrel Datwyler 
5279ecc03d95STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
5280ecc03d95STyrel Datwyler 
5281ecc03d95STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
5282ecc03d95STyrel Datwyler 		ibmvfc_dbg(vhost, "Send NVMe fabric login\n");
5283ecc03d95STyrel Datwyler 	else
5284ecc03d95STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5285ecc03d95STyrel Datwyler }
5286ecc03d95STyrel Datwyler 
ibmvfc_fabric_login_scsi_done(struct ibmvfc_event * evt)5287ecc03d95STyrel Datwyler static void ibmvfc_fabric_login_scsi_done(struct ibmvfc_event *evt)
5288ecc03d95STyrel Datwyler {
5289ecc03d95STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5290ecc03d95STyrel Datwyler 	struct ibmvfc_fabric_login_mad *rsp = &evt->xfer_iu->fabric_login;
5291ecc03d95STyrel Datwyler 	u32 mad_status = be16_to_cpu(rsp->common.status);
5292ecc03d95STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5293ecc03d95STyrel Datwyler 
5294ecc03d95STyrel Datwyler 	switch (mad_status) {
5295ecc03d95STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
52963831863fSTyrel Datwyler 		fc_host_port_id(vhost->host) = be64_to_cpu(rsp->nport_id);
5297ecc03d95STyrel Datwyler 		ibmvfc_dbg(vhost, "SCSI fabric login succeeded\n");
5298ecc03d95STyrel Datwyler 		break;
5299ecc03d95STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5300ecc03d95STyrel Datwyler 		if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
5301ecc03d95STyrel Datwyler 			level += ibmvfc_retry_host_init(vhost);
5302ecc03d95STyrel Datwyler 		else
5303ecc03d95STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5304ecc03d95STyrel Datwyler 		ibmvfc_log(vhost, level, "SCSI fabric login failed: %s (%x:%x)\n",
5305ecc03d95STyrel Datwyler 			   ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
5306ecc03d95STyrel Datwyler 			   be16_to_cpu(rsp->status), be16_to_cpu(rsp->error));
5307ecc03d95STyrel Datwyler 		ibmvfc_free_event(evt);
5308ecc03d95STyrel Datwyler 		return;
5309ecc03d95STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5310ecc03d95STyrel Datwyler 		ibmvfc_free_event(evt);
5311ecc03d95STyrel Datwyler 		return;
5312ecc03d95STyrel Datwyler 	default:
5313ecc03d95STyrel Datwyler 		dev_err(vhost->dev, "Invalid SCSI fabric login response: 0x%x\n", mad_status);
5314ecc03d95STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5315ecc03d95STyrel Datwyler 		break;
5316ecc03d95STyrel Datwyler 	}
5317ecc03d95STyrel Datwyler 
5318ecc03d95STyrel Datwyler 	ibmvfc_free_event(evt);
5319ecc03d95STyrel Datwyler 
5320ecc03d95STyrel Datwyler 	if (vhost->do_nvme_login) {
5321ecc03d95STyrel Datwyler 		ibmvfc_fabric_login_nvme(vhost);
5322ecc03d95STyrel Datwyler 	} else {
5323ecc03d95STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
5324ecc03d95STyrel Datwyler 		wake_up(&vhost->work_wait_q);
5325ecc03d95STyrel Datwyler 	}
5326ecc03d95STyrel Datwyler }
5327ecc03d95STyrel Datwyler 
ibmvfc_fabric_login_scsi(struct ibmvfc_host * vhost)5328ecc03d95STyrel Datwyler static void ibmvfc_fabric_login_scsi(struct ibmvfc_host *vhost)
5329ecc03d95STyrel Datwyler {
5330ecc03d95STyrel Datwyler 	struct ibmvfc_fabric_login_mad *mad;
5331ecc03d95STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
5332ecc03d95STyrel Datwyler 
5333ecc03d95STyrel Datwyler 	if (!evt) {
5334ecc03d95STyrel Datwyler 		ibmvfc_retry_host_init(vhost);
5335ecc03d95STyrel Datwyler 		return;
5336ecc03d95STyrel Datwyler 	}
5337ecc03d95STyrel Datwyler 
5338ecc03d95STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_fabric_login_scsi_done, IBMVFC_MAD_FORMAT);
5339ecc03d95STyrel Datwyler 	mad = &evt->iu.fabric_login;
5340ecc03d95STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
5341ecc03d95STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5342ecc03d95STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_FABRIC_LOGIN);
5343ecc03d95STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad));
5344ecc03d95STyrel Datwyler 
5345ecc03d95STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
5346ecc03d95STyrel Datwyler 
5347ecc03d95STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
5348ecc03d95STyrel Datwyler 		ibmvfc_dbg(vhost, "Send SCSI fabric login\n");
5349ecc03d95STyrel Datwyler 	else
5350ecc03d95STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5351ecc03d95STyrel Datwyler }
5352ecc03d95STyrel Datwyler 
ibmvfc_channel_setup_done(struct ibmvfc_event * evt)5353848c7085STyrel Datwyler static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt)
5354848c7085STyrel Datwyler {
5355848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5356848c7085STyrel Datwyler 	struct ibmvfc_channel_setup *setup = vhost->channel_setup_buf;
5357ecc03d95STyrel Datwyler 	struct ibmvfc_channels *scsi = &vhost->scsi_scrqs;
5358ecc03d95STyrel Datwyler 	struct ibmvfc_channels *nvme = &vhost->nvme_scrqs;
5359848c7085STyrel Datwyler 	u32 mad_status = be16_to_cpu(evt->xfer_iu->channel_setup.common.status);
5360848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5361ecc03d95STyrel Datwyler 	int flags, i;
5362848c7085STyrel Datwyler 
5363848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
5364848c7085STyrel Datwyler 
5365848c7085STyrel Datwyler 	switch (mad_status) {
5366848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
5367848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "Channel Setup succeeded\n");
5368848c7085STyrel Datwyler 		flags = be32_to_cpu(setup->flags);
5369848c7085STyrel Datwyler 		vhost->do_enquiry = 0;
5370ecc03d95STyrel Datwyler 		scsi->active_queues = be32_to_cpu(setup->num_scsi_subq_channels);
5371ecc03d95STyrel Datwyler 		nvme->active_queues = be32_to_cpu(setup->num_nvme_subq_channels);
5372848c7085STyrel Datwyler 
5373848c7085STyrel Datwyler 		if (flags & IBMVFC_CHANNELS_CANCELED) {
5374848c7085STyrel Datwyler 			ibmvfc_dbg(vhost, "Channels Canceled\n");
5375848c7085STyrel Datwyler 			vhost->using_channels = 0;
5376ecc03d95STyrel Datwyler 			break;
5377848c7085STyrel Datwyler 		}
5378ecc03d95STyrel Datwyler 
5379ecc03d95STyrel Datwyler 		if (scsi->active_queues || nvme->active_queues)
5380ecc03d95STyrel Datwyler 			vhost->using_channels = 1;
5381ecc03d95STyrel Datwyler 		for (i = 0; i < scsi->active_queues; i++)
5382ecc03d95STyrel Datwyler 			scsi->scrqs[i].vios_cookie =
5383ecc03d95STyrel Datwyler 				be64_to_cpu(setup->channel_handles[i]);
5384ecc03d95STyrel Datwyler 		for (i = 0; i < nvme->active_queues; i++)
5385ecc03d95STyrel Datwyler 			nvme->scrqs[i].vios_cookie =
5386ecc03d95STyrel Datwyler 				be64_to_cpu(setup->channel_handles[scsi->active_queues + i]);
5387ecc03d95STyrel Datwyler 
5388ecc03d95STyrel Datwyler 		ibmvfc_dbg(vhost, "Using %u SCSI channels\n",
5389ecc03d95STyrel Datwyler 			   scsi->active_queues);
5390ecc03d95STyrel Datwyler 		ibmvfc_dbg(vhost, "Using %u NVMe channels\n",
5391ecc03d95STyrel Datwyler 			   nvme->active_queues);
5392848c7085STyrel Datwyler 		break;
5393848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5394848c7085STyrel Datwyler 		level += ibmvfc_retry_host_init(vhost);
5395848c7085STyrel Datwyler 		ibmvfc_log(vhost, level, "Channel Setup failed\n");
5396848c7085STyrel Datwyler 		fallthrough;
5397848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5398848c7085STyrel Datwyler 		return;
5399848c7085STyrel Datwyler 	default:
5400848c7085STyrel Datwyler 		dev_err(vhost->dev, "Invalid Channel Setup response: 0x%x\n",
5401848c7085STyrel Datwyler 			mad_status);
5402848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5403848c7085STyrel Datwyler 		return;
5404848c7085STyrel Datwyler 	}
5405848c7085STyrel Datwyler 
5406ecc03d95STyrel Datwyler 	if (vhost->do_scsi_login) {
5407ecc03d95STyrel Datwyler 		ibmvfc_fabric_login_scsi(vhost);
5408ecc03d95STyrel Datwyler 	} else {
5409848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
5410848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
5411848c7085STyrel Datwyler 	}
5412ecc03d95STyrel Datwyler }
5413848c7085STyrel Datwyler 
ibmvfc_channel_setup(struct ibmvfc_host * vhost)5414848c7085STyrel Datwyler static void ibmvfc_channel_setup(struct ibmvfc_host *vhost)
5415848c7085STyrel Datwyler {
5416848c7085STyrel Datwyler 	struct ibmvfc_channel_setup_mad *mad;
5417848c7085STyrel Datwyler 	struct ibmvfc_channel_setup *setup_buf = vhost->channel_setup_buf;
5418848c7085STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
5419ecc03d95STyrel Datwyler 	struct ibmvfc_channels *scsi = &vhost->scsi_scrqs;
5420ecc03d95STyrel Datwyler 	struct ibmvfc_channels *nvme = &vhost->nvme_scrqs;
5421ecc03d95STyrel Datwyler 	unsigned int scsi_channels =
5422ecc03d95STyrel Datwyler 		min(scsi->desired_queues, vhost->max_vios_scsi_channels);
5423ecc03d95STyrel Datwyler 	unsigned int nvme_channels =
5424ecc03d95STyrel Datwyler 		min(nvme->desired_queues, vhost->max_vios_nvme_channels);
5425848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5426848c7085STyrel Datwyler 	int i;
5427848c7085STyrel Datwyler 
5428848c7085STyrel Datwyler 	if (!evt) {
5429848c7085STyrel Datwyler 		ibmvfc_log(vhost, level, "Channel Setup failed: no available events\n");
5430848c7085STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
5431848c7085STyrel Datwyler 		return;
5432848c7085STyrel Datwyler 	}
5433848c7085STyrel Datwyler 
5434848c7085STyrel Datwyler 	memset(setup_buf, 0, sizeof(*setup_buf));
5435ecc03d95STyrel Datwyler 	if (!scsi_channels && !nvme_channels)
5436848c7085STyrel Datwyler 		setup_buf->flags = cpu_to_be32(IBMVFC_CANCEL_CHANNELS);
5437848c7085STyrel Datwyler 	else {
5438ecc03d95STyrel Datwyler 		setup_buf->num_scsi_subq_channels = cpu_to_be32(scsi_channels);
5439ecc03d95STyrel Datwyler 		setup_buf->num_nvme_subq_channels = cpu_to_be32(nvme_channels);
5440ecc03d95STyrel Datwyler 		for (i = 0; i < scsi_channels; i++)
5441ecc03d95STyrel Datwyler 			setup_buf->channel_handles[i] =
5442ecc03d95STyrel Datwyler 				cpu_to_be64(scsi->scrqs[i].cookie);
5443ecc03d95STyrel Datwyler 		for (i = 0; i < nvme_channels; i++)
5444ecc03d95STyrel Datwyler 			setup_buf->channel_handles[scsi_channels + i] =
5445ecc03d95STyrel Datwyler 				cpu_to_be64(nvme->scrqs[i].cookie);
5446848c7085STyrel Datwyler 	}
5447848c7085STyrel Datwyler 
5448848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_channel_setup_done, IBMVFC_MAD_FORMAT);
5449848c7085STyrel Datwyler 	mad = &evt->iu.channel_setup;
5450848c7085STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
5451848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5452848c7085STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_CHANNEL_SETUP);
5453848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad));
5454848c7085STyrel Datwyler 	mad->buffer.va = cpu_to_be64(vhost->channel_setup_dma);
5455848c7085STyrel Datwyler 	mad->buffer.len = cpu_to_be32(sizeof(*vhost->channel_setup_buf));
5456848c7085STyrel Datwyler 
5457848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
5458848c7085STyrel Datwyler 
5459848c7085STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
5460848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "Sent channel setup\n");
5461848c7085STyrel Datwyler 	else
5462848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
5463848c7085STyrel Datwyler }
5464848c7085STyrel Datwyler 
ibmvfc_channel_enquiry_done(struct ibmvfc_event * evt)5465848c7085STyrel Datwyler static void ibmvfc_channel_enquiry_done(struct ibmvfc_event *evt)
5466848c7085STyrel Datwyler {
5467848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5468848c7085STyrel Datwyler 	struct ibmvfc_channel_enquiry *rsp = &evt->xfer_iu->channel_enquiry;
5469848c7085STyrel Datwyler 	u32 mad_status = be16_to_cpu(rsp->common.status);
5470848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5471848c7085STyrel Datwyler 
5472848c7085STyrel Datwyler 	switch (mad_status) {
5473848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
5474848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "Channel Enquiry succeeded\n");
5475848c7085STyrel Datwyler 		vhost->max_vios_scsi_channels = be32_to_cpu(rsp->num_scsi_subq_channels);
5476ecc03d95STyrel Datwyler 		vhost->max_vios_nvme_channels = be32_to_cpu(rsp->num_nvme_subq_channels);
5477848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5478848c7085STyrel Datwyler 		break;
5479848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5480848c7085STyrel Datwyler 		level += ibmvfc_retry_host_init(vhost);
5481848c7085STyrel Datwyler 		ibmvfc_log(vhost, level, "Channel Enquiry failed\n");
5482848c7085STyrel Datwyler 		fallthrough;
5483848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5484848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5485848c7085STyrel Datwyler 		return;
5486848c7085STyrel Datwyler 	default:
5487848c7085STyrel Datwyler 		dev_err(vhost->dev, "Invalid Channel Enquiry response: 0x%x\n",
5488848c7085STyrel Datwyler 			mad_status);
5489848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5490848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5491848c7085STyrel Datwyler 		return;
5492848c7085STyrel Datwyler 	}
5493848c7085STyrel Datwyler 
5494848c7085STyrel Datwyler 	ibmvfc_channel_setup(vhost);
5495848c7085STyrel Datwyler }
5496848c7085STyrel Datwyler 
ibmvfc_channel_enquiry(struct ibmvfc_host * vhost)5497848c7085STyrel Datwyler static void ibmvfc_channel_enquiry(struct ibmvfc_host *vhost)
5498848c7085STyrel Datwyler {
5499848c7085STyrel Datwyler 	struct ibmvfc_channel_enquiry *mad;
5500848c7085STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
5501848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5502848c7085STyrel Datwyler 
5503848c7085STyrel Datwyler 	if (!evt) {
5504848c7085STyrel Datwyler 		ibmvfc_log(vhost, level, "Channel Enquiry failed: no available events\n");
5505848c7085STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
5506848c7085STyrel Datwyler 		return;
5507848c7085STyrel Datwyler 	}
5508848c7085STyrel Datwyler 
5509848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_channel_enquiry_done, IBMVFC_MAD_FORMAT);
5510848c7085STyrel Datwyler 	mad = &evt->iu.channel_enquiry;
5511848c7085STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
5512848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5513848c7085STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_CHANNEL_ENQUIRY);
5514848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(*mad));
5515848c7085STyrel Datwyler 
5516848c7085STyrel Datwyler 	if (mig_channels_only)
5517848c7085STyrel Datwyler 		mad->flags |= cpu_to_be32(IBMVFC_NO_CHANNELS_TO_CRQ_SUPPORT);
5518848c7085STyrel Datwyler 	if (mig_no_less_channels)
5519848c7085STyrel Datwyler 		mad->flags |= cpu_to_be32(IBMVFC_NO_N_TO_M_CHANNELS_SUPPORT);
5520848c7085STyrel Datwyler 
5521848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
5522848c7085STyrel Datwyler 
5523848c7085STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
5524848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "Send channel enquiry\n");
5525848c7085STyrel Datwyler 	else
5526848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5527848c7085STyrel Datwyler }
5528848c7085STyrel Datwyler 
5529848c7085STyrel Datwyler /**
5530848c7085STyrel Datwyler  * ibmvfc_npiv_login_done - Completion handler for NPIV Login
5531848c7085STyrel Datwyler  * @evt:	ibmvfc event struct
5532848c7085STyrel Datwyler  *
5533848c7085STyrel Datwyler  **/
ibmvfc_npiv_login_done(struct ibmvfc_event * evt)5534848c7085STyrel Datwyler static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
5535848c7085STyrel Datwyler {
5536848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5537848c7085STyrel Datwyler 	u32 mad_status = be16_to_cpu(evt->xfer_iu->npiv_login.common.status);
5538848c7085STyrel Datwyler 	struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp;
5539848c7085STyrel Datwyler 	unsigned int npiv_max_sectors;
5540848c7085STyrel Datwyler 	int level = IBMVFC_DEFAULT_LOG_LEVEL;
5541848c7085STyrel Datwyler 
5542848c7085STyrel Datwyler 	switch (mad_status) {
5543848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
5544848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5545848c7085STyrel Datwyler 		break;
5546848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5547848c7085STyrel Datwyler 		if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
5548848c7085STyrel Datwyler 			level += ibmvfc_retry_host_init(vhost);
5549848c7085STyrel Datwyler 		else
5550848c7085STyrel Datwyler 			ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5551848c7085STyrel Datwyler 		ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n",
5552848c7085STyrel Datwyler 			   ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
5553848c7085STyrel Datwyler 						be16_to_cpu(rsp->status), be16_to_cpu(rsp->error));
5554848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5555848c7085STyrel Datwyler 		return;
5556848c7085STyrel Datwyler 	case IBMVFC_MAD_CRQ_ERROR:
5557848c7085STyrel Datwyler 		ibmvfc_retry_host_init(vhost);
5558848c7085STyrel Datwyler 		fallthrough;
5559848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5560848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5561848c7085STyrel Datwyler 		return;
5562848c7085STyrel Datwyler 	default:
5563848c7085STyrel Datwyler 		dev_err(vhost->dev, "Invalid NPIV Login response: 0x%x\n", mad_status);
5564848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5565848c7085STyrel Datwyler 		ibmvfc_free_event(evt);
5566848c7085STyrel Datwyler 		return;
5567848c7085STyrel Datwyler 	}
5568848c7085STyrel Datwyler 
5569848c7085STyrel Datwyler 	vhost->client_migrated = 0;
5570848c7085STyrel Datwyler 
5571848c7085STyrel Datwyler 	if (!(be32_to_cpu(rsp->flags) & IBMVFC_NATIVE_FC)) {
5572848c7085STyrel Datwyler 		dev_err(vhost->dev, "Virtual adapter does not support FC. %x\n",
5573848c7085STyrel Datwyler 			rsp->flags);
5574848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5575848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
5576848c7085STyrel Datwyler 		return;
5577848c7085STyrel Datwyler 	}
5578848c7085STyrel Datwyler 
5579848c7085STyrel Datwyler 	if (be32_to_cpu(rsp->max_cmds) <= IBMVFC_NUM_INTERNAL_REQ) {
5580848c7085STyrel Datwyler 		dev_err(vhost->dev, "Virtual adapter supported queue depth too small: %d\n",
5581848c7085STyrel Datwyler 			rsp->max_cmds);
5582848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5583848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
5584848c7085STyrel Datwyler 		return;
5585848c7085STyrel Datwyler 	}
5586848c7085STyrel Datwyler 
5587848c7085STyrel Datwyler 	vhost->logged_in = 1;
5588848c7085STyrel Datwyler 	npiv_max_sectors = min((uint)(be64_to_cpu(rsp->max_dma_len) >> 9), max_sectors);
5589848c7085STyrel Datwyler 	dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n",
5590848c7085STyrel Datwyler 		 rsp->partition_name, rsp->device_name, rsp->port_loc_code,
5591848c7085STyrel Datwyler 		 rsp->drc_name, npiv_max_sectors);
5592848c7085STyrel Datwyler 
5593848c7085STyrel Datwyler 	fc_host_fabric_name(vhost->host) = be64_to_cpu(rsp->node_name);
5594848c7085STyrel Datwyler 	fc_host_node_name(vhost->host) = be64_to_cpu(rsp->node_name);
5595848c7085STyrel Datwyler 	fc_host_port_name(vhost->host) = be64_to_cpu(rsp->port_name);
5596848c7085STyrel Datwyler 	fc_host_port_id(vhost->host) = be64_to_cpu(rsp->scsi_id);
5597848c7085STyrel Datwyler 	fc_host_port_type(vhost->host) = FC_PORTTYPE_NPIV;
5598848c7085STyrel Datwyler 	fc_host_supported_classes(vhost->host) = 0;
5599848c7085STyrel Datwyler 	if (be32_to_cpu(rsp->service_parms.class1_parms[0]) & 0x80000000)
5600848c7085STyrel Datwyler 		fc_host_supported_classes(vhost->host) |= FC_COS_CLASS1;
5601848c7085STyrel Datwyler 	if (be32_to_cpu(rsp->service_parms.class2_parms[0]) & 0x80000000)
5602848c7085STyrel Datwyler 		fc_host_supported_classes(vhost->host) |= FC_COS_CLASS2;
5603848c7085STyrel Datwyler 	if (be32_to_cpu(rsp->service_parms.class3_parms[0]) & 0x80000000)
5604848c7085STyrel Datwyler 		fc_host_supported_classes(vhost->host) |= FC_COS_CLASS3;
5605848c7085STyrel Datwyler 	fc_host_maxframe_size(vhost->host) =
5606848c7085STyrel Datwyler 		be16_to_cpu(rsp->service_parms.common.bb_rcv_sz) & 0x0fff;
5607848c7085STyrel Datwyler 
5608848c7085STyrel Datwyler 	vhost->host->can_queue = be32_to_cpu(rsp->max_cmds) - IBMVFC_NUM_INTERNAL_REQ;
5609848c7085STyrel Datwyler 	vhost->host->max_sectors = npiv_max_sectors;
5610848c7085STyrel Datwyler 
5611ecc03d95STyrel Datwyler 
5612ecc03d95STyrel Datwyler 	if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS)) {
5613ecc03d95STyrel Datwyler 		if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_SCSI))
5614ecc03d95STyrel Datwyler 			vhost->do_scsi_login = 1;
5615ecc03d95STyrel Datwyler 		if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NVMEOF))
5616ecc03d95STyrel Datwyler 			vhost->do_nvme_login = 1;
5617ecc03d95STyrel Datwyler 		if (vhost->do_enquiry)
5618848c7085STyrel Datwyler 			ibmvfc_channel_enquiry(vhost);
5619848c7085STyrel Datwyler 	} else {
5620848c7085STyrel Datwyler 		vhost->do_enquiry = 0;
5621848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
5622848c7085STyrel Datwyler 		wake_up(&vhost->work_wait_q);
5623848c7085STyrel Datwyler 	}
5624848c7085STyrel Datwyler }
5625848c7085STyrel Datwyler 
5626848c7085STyrel Datwyler /**
5627848c7085STyrel Datwyler  * ibmvfc_npiv_login - Sends NPIV login
5628848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
5629848c7085STyrel Datwyler  *
5630848c7085STyrel Datwyler  **/
ibmvfc_npiv_login(struct ibmvfc_host * vhost)5631848c7085STyrel Datwyler static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)
5632848c7085STyrel Datwyler {
5633848c7085STyrel Datwyler 	struct ibmvfc_npiv_login_mad *mad;
5634848c7085STyrel Datwyler 	struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
5635848c7085STyrel Datwyler 
5636848c7085STyrel Datwyler 	if (!evt) {
5637848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "NPIV Login failed: no available events\n");
5638848c7085STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
5639848c7085STyrel Datwyler 		return;
5640848c7085STyrel Datwyler 	}
5641848c7085STyrel Datwyler 
5642848c7085STyrel Datwyler 	ibmvfc_gather_partition_info(vhost);
5643848c7085STyrel Datwyler 	ibmvfc_set_login_info(vhost);
5644848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_npiv_login_done, IBMVFC_MAD_FORMAT);
5645848c7085STyrel Datwyler 
5646848c7085STyrel Datwyler 	memcpy(vhost->login_buf, &vhost->login_info, sizeof(vhost->login_info));
5647848c7085STyrel Datwyler 	mad = &evt->iu.npiv_login;
5648848c7085STyrel Datwyler 	memset(mad, 0, sizeof(struct ibmvfc_npiv_login_mad));
5649848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5650848c7085STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_NPIV_LOGIN);
5651848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(struct ibmvfc_npiv_login_mad));
5652848c7085STyrel Datwyler 	mad->buffer.va = cpu_to_be64(vhost->login_buf_dma);
5653848c7085STyrel Datwyler 	mad->buffer.len = cpu_to_be32(sizeof(*vhost->login_buf));
5654848c7085STyrel Datwyler 
5655848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
5656848c7085STyrel Datwyler 
5657848c7085STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
5658848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "Sent NPIV login\n");
5659848c7085STyrel Datwyler 	else
5660848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5661848c7085STyrel Datwyler }
5662848c7085STyrel Datwyler 
5663848c7085STyrel Datwyler /**
5664848c7085STyrel Datwyler  * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout
5665848c7085STyrel Datwyler  * @evt:		ibmvfc event struct
5666848c7085STyrel Datwyler  *
5667848c7085STyrel Datwyler  **/
ibmvfc_npiv_logout_done(struct ibmvfc_event * evt)5668848c7085STyrel Datwyler static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt)
5669848c7085STyrel Datwyler {
5670848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = evt->vhost;
5671848c7085STyrel Datwyler 	u32 mad_status = be16_to_cpu(evt->xfer_iu->npiv_logout.common.status);
5672848c7085STyrel Datwyler 
5673848c7085STyrel Datwyler 	ibmvfc_free_event(evt);
5674848c7085STyrel Datwyler 
5675848c7085STyrel Datwyler 	switch (mad_status) {
5676848c7085STyrel Datwyler 	case IBMVFC_MAD_SUCCESS:
5677848c7085STyrel Datwyler 		if (list_empty(&vhost->crq.sent) &&
5678848c7085STyrel Datwyler 		    vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) {
56793831863fSTyrel Datwyler 			ibmvfc_nvme_unregister(vhost);
5680848c7085STyrel Datwyler 			ibmvfc_init_host(vhost);
5681848c7085STyrel Datwyler 			return;
5682848c7085STyrel Datwyler 		}
5683848c7085STyrel Datwyler 		break;
5684848c7085STyrel Datwyler 	case IBMVFC_MAD_FAILED:
5685848c7085STyrel Datwyler 	case IBMVFC_MAD_NOT_SUPPORTED:
5686848c7085STyrel Datwyler 	case IBMVFC_MAD_CRQ_ERROR:
5687848c7085STyrel Datwyler 	case IBMVFC_MAD_DRIVER_FAILED:
5688848c7085STyrel Datwyler 	default:
5689848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status);
5690848c7085STyrel Datwyler 		break;
5691848c7085STyrel Datwyler 	}
5692848c7085STyrel Datwyler 
5693848c7085STyrel Datwyler 	ibmvfc_hard_reset_host(vhost);
5694848c7085STyrel Datwyler }
5695848c7085STyrel Datwyler 
5696848c7085STyrel Datwyler /**
5697848c7085STyrel Datwyler  * ibmvfc_npiv_logout - Issue an NPIV Logout
5698848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5699848c7085STyrel Datwyler  *
5700848c7085STyrel Datwyler  **/
ibmvfc_npiv_logout(struct ibmvfc_host * vhost)5701848c7085STyrel Datwyler static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
5702848c7085STyrel Datwyler {
5703848c7085STyrel Datwyler 	struct ibmvfc_npiv_logout_mad *mad;
5704848c7085STyrel Datwyler 	struct ibmvfc_event *evt;
5705848c7085STyrel Datwyler 
5706848c7085STyrel Datwyler 	evt = ibmvfc_get_reserved_event(&vhost->crq);
5707848c7085STyrel Datwyler 	if (!evt) {
5708848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "NPIV Logout failed: no available events\n");
5709848c7085STyrel Datwyler 		ibmvfc_hard_reset_host(vhost);
5710848c7085STyrel Datwyler 		return;
5711848c7085STyrel Datwyler 	}
5712848c7085STyrel Datwyler 
5713848c7085STyrel Datwyler 	ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
5714848c7085STyrel Datwyler 
5715848c7085STyrel Datwyler 	mad = &evt->iu.npiv_logout;
5716848c7085STyrel Datwyler 	memset(mad, 0, sizeof(*mad));
5717848c7085STyrel Datwyler 	mad->common.version = cpu_to_be32(1);
5718848c7085STyrel Datwyler 	mad->common.opcode = cpu_to_be32(IBMVFC_NPIV_LOGOUT);
5719848c7085STyrel Datwyler 	mad->common.length = cpu_to_be16(sizeof(struct ibmvfc_npiv_logout_mad));
5720848c7085STyrel Datwyler 
5721848c7085STyrel Datwyler 	ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT);
5722848c7085STyrel Datwyler 
5723848c7085STyrel Datwyler 	if (!ibmvfc_send_event(evt, vhost, default_timeout))
5724848c7085STyrel Datwyler 		ibmvfc_dbg(vhost, "Sent NPIV logout\n");
5725848c7085STyrel Datwyler 	else
5726848c7085STyrel Datwyler 		ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
5727848c7085STyrel Datwyler }
5728848c7085STyrel Datwyler 
5729848c7085STyrel Datwyler /**
5730848c7085STyrel Datwyler  * ibmvfc_dev_init_to_do - Is there target initialization work to do?
5731848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5732848c7085STyrel Datwyler  *
5733848c7085STyrel Datwyler  * Returns:
5734848c7085STyrel Datwyler  *	1 if work to do / 0 if not
5735848c7085STyrel Datwyler  **/
ibmvfc_dev_init_to_do(struct ibmvfc_host * vhost)5736848c7085STyrel Datwyler static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost)
5737848c7085STyrel Datwyler {
5738848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
5739848c7085STyrel Datwyler 
5740848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
5741848c7085STyrel Datwyler 		if (tgt->action == IBMVFC_TGT_ACTION_INIT ||
5742848c7085STyrel Datwyler 		    tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
5743848c7085STyrel Datwyler 			return 1;
5744848c7085STyrel Datwyler 	}
57450a3ab63eSTyrel Datwyler 	list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
57460a3ab63eSTyrel Datwyler 		if (tgt->action == IBMVFC_TGT_ACTION_INIT ||
57470a3ab63eSTyrel Datwyler 		    tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
57480a3ab63eSTyrel Datwyler 			return 1;
57490a3ab63eSTyrel Datwyler 	}
5750848c7085STyrel Datwyler 
5751848c7085STyrel Datwyler 	return 0;
5752848c7085STyrel Datwyler }
5753848c7085STyrel Datwyler 
5754848c7085STyrel Datwyler /**
5755848c7085STyrel Datwyler  * ibmvfc_dev_logo_to_do - Is there target logout work to do?
5756848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5757848c7085STyrel Datwyler  *
5758848c7085STyrel Datwyler  * Returns:
5759848c7085STyrel Datwyler  *	1 if work to do / 0 if not
5760848c7085STyrel Datwyler  **/
ibmvfc_dev_logo_to_do(struct ibmvfc_host * vhost)5761848c7085STyrel Datwyler static int ibmvfc_dev_logo_to_do(struct ibmvfc_host *vhost)
5762848c7085STyrel Datwyler {
5763848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
5764848c7085STyrel Datwyler 
5765848c7085STyrel Datwyler 	list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
5766848c7085STyrel Datwyler 		if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT ||
5767848c7085STyrel Datwyler 		    tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT)
5768848c7085STyrel Datwyler 			return 1;
5769848c7085STyrel Datwyler 	}
57700a3ab63eSTyrel Datwyler 	list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
57710a3ab63eSTyrel Datwyler 		if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT ||
57720a3ab63eSTyrel Datwyler 		    tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT)
57730a3ab63eSTyrel Datwyler 			return 1;
57740a3ab63eSTyrel Datwyler 	}
5775848c7085STyrel Datwyler 	return 0;
5776848c7085STyrel Datwyler }
5777848c7085STyrel Datwyler 
5778848c7085STyrel Datwyler /**
5779848c7085STyrel Datwyler  * __ibmvfc_work_to_do - Is there task level work to do? (no locking)
5780848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5781848c7085STyrel Datwyler  *
5782848c7085STyrel Datwyler  * Returns:
5783848c7085STyrel Datwyler  *	1 if work to do / 0 if not
5784848c7085STyrel Datwyler  **/
__ibmvfc_work_to_do(struct ibmvfc_host * vhost)5785848c7085STyrel Datwyler static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
5786848c7085STyrel Datwyler {
5787848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
5788848c7085STyrel Datwyler 
5789848c7085STyrel Datwyler 	if (kthread_should_stop())
5790848c7085STyrel Datwyler 		return 1;
5791848c7085STyrel Datwyler 	switch (vhost->action) {
5792848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_NONE:
5793848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_INIT_WAIT:
5794848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_LOGO_WAIT:
5795848c7085STyrel Datwyler 		return 0;
5796848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_INIT:
5797848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_QUERY_TGTS:
5798848c7085STyrel Datwyler 		if (vhost->discovery_threads == disc_threads)
5799848c7085STyrel Datwyler 			return 0;
5800848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
5801848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT)
5802848c7085STyrel Datwyler 				return 1;
58030a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
58040a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT)
58050a3ab63eSTyrel Datwyler 				return 1;
5806848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
5807848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
5808848c7085STyrel Datwyler 				return 0;
58090a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
58100a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
58110a3ab63eSTyrel Datwyler 				return 0;
5812848c7085STyrel Datwyler 		return 1;
5813848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_DEL:
5814848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
5815848c7085STyrel Datwyler 		if (vhost->discovery_threads == disc_threads)
5816848c7085STyrel Datwyler 			return 0;
5817848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
5818848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT)
5819848c7085STyrel Datwyler 				return 1;
58200a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
58210a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT)
58220a3ab63eSTyrel Datwyler 				return 1;
5823848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
5824848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT)
5825848c7085STyrel Datwyler 				return 0;
58260a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
58270a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT)
58280a3ab63eSTyrel Datwyler 				return 0;
5829848c7085STyrel Datwyler 		return 1;
5830848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_LOGO:
5831848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_INIT:
5832848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_ALLOC_TGTS:
5833848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_QUERY:
5834848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_RESET:
5835848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_REENABLE:
5836848c7085STyrel Datwyler 	default:
5837848c7085STyrel Datwyler 		break;
5838848c7085STyrel Datwyler 	}
5839848c7085STyrel Datwyler 
5840848c7085STyrel Datwyler 	return 1;
5841848c7085STyrel Datwyler }
5842848c7085STyrel Datwyler 
5843848c7085STyrel Datwyler /**
5844848c7085STyrel Datwyler  * ibmvfc_work_to_do - Is there task level work to do?
5845848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5846848c7085STyrel Datwyler  *
5847848c7085STyrel Datwyler  * Returns:
5848848c7085STyrel Datwyler  *	1 if work to do / 0 if not
5849848c7085STyrel Datwyler  **/
ibmvfc_work_to_do(struct ibmvfc_host * vhost)5850848c7085STyrel Datwyler static int ibmvfc_work_to_do(struct ibmvfc_host *vhost)
5851848c7085STyrel Datwyler {
5852848c7085STyrel Datwyler 	unsigned long flags;
5853848c7085STyrel Datwyler 	int rc;
5854848c7085STyrel Datwyler 
5855848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
5856848c7085STyrel Datwyler 	rc = __ibmvfc_work_to_do(vhost);
5857848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
5858848c7085STyrel Datwyler 	return rc;
5859848c7085STyrel Datwyler }
5860848c7085STyrel Datwyler 
5861848c7085STyrel Datwyler /**
5862848c7085STyrel Datwyler  * ibmvfc_log_ae - Log async events if necessary
5863848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5864848c7085STyrel Datwyler  * @events:		events to log
5865848c7085STyrel Datwyler  *
5866848c7085STyrel Datwyler  **/
ibmvfc_log_ae(struct ibmvfc_host * vhost,int events)5867848c7085STyrel Datwyler static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events)
5868848c7085STyrel Datwyler {
5869848c7085STyrel Datwyler 	if (events & IBMVFC_AE_RSCN)
5870848c7085STyrel Datwyler 		fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_RSCN, 0);
5871848c7085STyrel Datwyler 	if ((events & IBMVFC_AE_LINKDOWN) &&
5872848c7085STyrel Datwyler 	    vhost->state >= IBMVFC_HALTED)
5873848c7085STyrel Datwyler 		fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
5874848c7085STyrel Datwyler 	if ((events & IBMVFC_AE_LINKUP) &&
5875848c7085STyrel Datwyler 	    vhost->state == IBMVFC_INITIALIZING)
5876848c7085STyrel Datwyler 		fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKUP, 0);
5877848c7085STyrel Datwyler }
5878848c7085STyrel Datwyler 
5879848c7085STyrel Datwyler /**
5880696d1cc2STyrel Datwyler  * ibmvfc_tgt_add_nvme_rport - Tell the FC transport about a new remote port
5881696d1cc2STyrel Datwyler  * @tgt:		ibmvfc target struct
5882696d1cc2STyrel Datwyler  *
5883696d1cc2STyrel Datwyler  **/
ibmvfc_tgt_add_nvme_rport(struct ibmvfc_target * tgt)5884696d1cc2STyrel Datwyler static void ibmvfc_tgt_add_nvme_rport(struct ibmvfc_target *tgt)
5885696d1cc2STyrel Datwyler {
5886696d1cc2STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
5887696d1cc2STyrel Datwyler 	struct nvme_fc_remote_port *rport;
5888696d1cc2STyrel Datwyler 	unsigned long flags;
5889696d1cc2STyrel Datwyler 
5890696d1cc2STyrel Datwyler 	tgt_dbg(tgt, "Adding NVMe rport\n");
5891696d1cc2STyrel Datwyler 	ibmvfc_nvme_register_remoteport(tgt);
5892696d1cc2STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
5893696d1cc2STyrel Datwyler 	rport = tgt->nvme_remote_port;
5894696d1cc2STyrel Datwyler 
5895696d1cc2STyrel Datwyler 	if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
5896696d1cc2STyrel Datwyler 		tgt_dbg(tgt, "Deleting NVMe rport\n");
5897696d1cc2STyrel Datwyler 		list_del(&tgt->queue);
5898696d1cc2STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT);
5899696d1cc2STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
5900696d1cc2STyrel Datwyler 		ibmvfc_nvme_unregister_remoteport(tgt);
5901696d1cc2STyrel Datwyler 		timer_delete_sync(&tgt->timer);
5902696d1cc2STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
5903696d1cc2STyrel Datwyler 		return;
5904696d1cc2STyrel Datwyler 	} else if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) {
5905696d1cc2STyrel Datwyler 		tgt_dbg(tgt, "Deleting NVMe rport with outstanding I/O\n");
5906696d1cc2STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT);
5907696d1cc2STyrel Datwyler 		tgt->init_retries = 0;
5908696d1cc2STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
5909696d1cc2STyrel Datwyler 		ibmvfc_nvme_unregister_remoteport(tgt);
5910696d1cc2STyrel Datwyler 		return;
5911696d1cc2STyrel Datwyler 	} else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) {
5912696d1cc2STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
5913696d1cc2STyrel Datwyler 		return;
5914696d1cc2STyrel Datwyler 	}
5915696d1cc2STyrel Datwyler 
5916696d1cc2STyrel Datwyler 	if (rport) {
5917696d1cc2STyrel Datwyler 		tgt_dbg(tgt, "NVMe rport add succeeded\n");
5918696d1cc2STyrel Datwyler 		tgt->target_id = tgt->nvme_remote_port->port_id;
5919696d1cc2STyrel Datwyler 	} else
5920696d1cc2STyrel Datwyler 		tgt_dbg(tgt, "NVMe rport add failed\n");
5921696d1cc2STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
5922696d1cc2STyrel Datwyler }
5923696d1cc2STyrel Datwyler 
5924696d1cc2STyrel Datwyler /**
5925848c7085STyrel Datwyler  * ibmvfc_tgt_add_rport - Tell the FC transport about a new remote port
5926848c7085STyrel Datwyler  * @tgt:		ibmvfc target struct
5927848c7085STyrel Datwyler  *
5928848c7085STyrel Datwyler  **/
ibmvfc_tgt_add_rport(struct ibmvfc_target * tgt)5929848c7085STyrel Datwyler static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
5930848c7085STyrel Datwyler {
5931848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = tgt->vhost;
5932848c7085STyrel Datwyler 	struct fc_rport *rport;
5933848c7085STyrel Datwyler 	unsigned long flags;
5934848c7085STyrel Datwyler 
5935848c7085STyrel Datwyler 	tgt_dbg(tgt, "Adding rport\n");
5936848c7085STyrel Datwyler 	rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
5937848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
5938848c7085STyrel Datwyler 
5939848c7085STyrel Datwyler 	if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
5940848c7085STyrel Datwyler 		tgt_dbg(tgt, "Deleting rport\n");
5941848c7085STyrel Datwyler 		list_del(&tgt->queue);
5942848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT);
5943848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
5944848c7085STyrel Datwyler 		fc_remote_port_delete(rport);
5945848c7085STyrel Datwyler 		timer_delete_sync(&tgt->timer);
5946848c7085STyrel Datwyler 		kref_put(&tgt->kref, ibmvfc_release_tgt);
5947848c7085STyrel Datwyler 		return;
5948848c7085STyrel Datwyler 	} else if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) {
5949848c7085STyrel Datwyler 		tgt_dbg(tgt, "Deleting rport with outstanding I/O\n");
5950848c7085STyrel Datwyler 		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT);
5951848c7085STyrel Datwyler 		tgt->rport = NULL;
5952848c7085STyrel Datwyler 		tgt->init_retries = 0;
5953848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
5954848c7085STyrel Datwyler 		fc_remote_port_delete(rport);
5955848c7085STyrel Datwyler 		return;
5956848c7085STyrel Datwyler 	} else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) {
5957848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
5958848c7085STyrel Datwyler 		return;
5959848c7085STyrel Datwyler 	}
5960848c7085STyrel Datwyler 
5961848c7085STyrel Datwyler 	if (rport) {
5962848c7085STyrel Datwyler 		tgt_dbg(tgt, "rport add succeeded\n");
5963848c7085STyrel Datwyler 		tgt->rport = rport;
5964848c7085STyrel Datwyler 		rport->maxframe_size = be16_to_cpu(tgt->service_parms.common.bb_rcv_sz) & 0x0fff;
5965848c7085STyrel Datwyler 		rport->supported_classes = 0;
5966848c7085STyrel Datwyler 		tgt->target_id = rport->scsi_target_id;
5967848c7085STyrel Datwyler 		if (be32_to_cpu(tgt->service_parms.class1_parms[0]) & 0x80000000)
5968848c7085STyrel Datwyler 			rport->supported_classes |= FC_COS_CLASS1;
5969848c7085STyrel Datwyler 		if (be32_to_cpu(tgt->service_parms.class2_parms[0]) & 0x80000000)
5970848c7085STyrel Datwyler 			rport->supported_classes |= FC_COS_CLASS2;
5971848c7085STyrel Datwyler 		if (be32_to_cpu(tgt->service_parms.class3_parms[0]) & 0x80000000)
5972848c7085STyrel Datwyler 			rport->supported_classes |= FC_COS_CLASS3;
5973848c7085STyrel Datwyler 	} else
5974848c7085STyrel Datwyler 		tgt_dbg(tgt, "rport add failed\n");
5975848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
5976848c7085STyrel Datwyler }
5977848c7085STyrel Datwyler 
5978848c7085STyrel Datwyler /**
5979848c7085STyrel Datwyler  * ibmvfc_do_work - Do task level work
5980848c7085STyrel Datwyler  * @vhost:		ibmvfc host struct
5981848c7085STyrel Datwyler  *
5982848c7085STyrel Datwyler  **/
ibmvfc_do_work(struct ibmvfc_host * vhost)5983848c7085STyrel Datwyler static void ibmvfc_do_work(struct ibmvfc_host *vhost)
5984848c7085STyrel Datwyler {
5985848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
5986848c7085STyrel Datwyler 	unsigned long flags;
5987848c7085STyrel Datwyler 	struct fc_rport *rport;
5988696d1cc2STyrel Datwyler 	struct nvme_fc_remote_port *nvme_rport;
5989848c7085STyrel Datwyler 	LIST_HEAD(purge);
5990848c7085STyrel Datwyler 	int rc;
5991848c7085STyrel Datwyler 
5992848c7085STyrel Datwyler 	ibmvfc_log_ae(vhost, vhost->events_to_log);
5993848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
5994848c7085STyrel Datwyler 	vhost->events_to_log = 0;
5995848c7085STyrel Datwyler 	switch (vhost->action) {
5996848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_NONE:
5997848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_LOGO_WAIT:
5998848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_INIT_WAIT:
5999848c7085STyrel Datwyler 		break;
6000848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_RESET:
6001848c7085STyrel Datwyler 		list_splice_init(&vhost->purge, &purge);
6002848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
6003848c7085STyrel Datwyler 		ibmvfc_complete_purge(&purge);
60043831863fSTyrel Datwyler 		ibmvfc_nvme_unregister(vhost);
6005848c7085STyrel Datwyler 		rc = ibmvfc_reset_crq(vhost);
6006848c7085STyrel Datwyler 
6007848c7085STyrel Datwyler 		spin_lock_irqsave(vhost->host->host_lock, flags);
6008848c7085STyrel Datwyler 		if (!rc || rc == H_CLOSED)
6009848c7085STyrel Datwyler 			vio_enable_interrupts(to_vio_dev(vhost->dev));
6010848c7085STyrel Datwyler 		if (vhost->action == IBMVFC_HOST_ACTION_RESET) {
6011848c7085STyrel Datwyler 			/*
6012848c7085STyrel Datwyler 			 * The only action we could have changed to would have
6013848c7085STyrel Datwyler 			 * been reenable, in which case, we skip the rest of
6014848c7085STyrel Datwyler 			 * this path and wait until we've done the re-enable
6015848c7085STyrel Datwyler 			 * before sending the crq init.
6016848c7085STyrel Datwyler 			 */
6017848c7085STyrel Datwyler 			vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
6018848c7085STyrel Datwyler 
6019848c7085STyrel Datwyler 			if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
6020848c7085STyrel Datwyler 			    (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
6021848c7085STyrel Datwyler 				ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
6022848c7085STyrel Datwyler 				dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
6023848c7085STyrel Datwyler 			}
6024848c7085STyrel Datwyler 		}
6025848c7085STyrel Datwyler 		break;
6026848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_REENABLE:
6027848c7085STyrel Datwyler 		list_splice_init(&vhost->purge, &purge);
6028848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
6029848c7085STyrel Datwyler 		ibmvfc_complete_purge(&purge);
6030848c7085STyrel Datwyler 		rc = ibmvfc_reenable_crq_queue(vhost);
6031848c7085STyrel Datwyler 
6032848c7085STyrel Datwyler 		spin_lock_irqsave(vhost->host->host_lock, flags);
6033848c7085STyrel Datwyler 		if (vhost->action == IBMVFC_HOST_ACTION_REENABLE) {
6034848c7085STyrel Datwyler 			/*
6035848c7085STyrel Datwyler 			 * The only action we could have changed to would have
6036848c7085STyrel Datwyler 			 * been reset, in which case, we skip the rest of this
6037848c7085STyrel Datwyler 			 * path and wait until we've done the reset before
6038848c7085STyrel Datwyler 			 * sending the crq init.
6039848c7085STyrel Datwyler 			 */
6040848c7085STyrel Datwyler 			vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
6041848c7085STyrel Datwyler 			if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
6042848c7085STyrel Datwyler 				ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
6043848c7085STyrel Datwyler 				dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc);
6044848c7085STyrel Datwyler 			}
6045848c7085STyrel Datwyler 		}
6046848c7085STyrel Datwyler 		break;
6047848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_LOGO:
6048848c7085STyrel Datwyler 		vhost->job_step(vhost);
6049848c7085STyrel Datwyler 		break;
6050848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_INIT:
6051848c7085STyrel Datwyler 		BUG_ON(vhost->state != IBMVFC_INITIALIZING);
6052848c7085STyrel Datwyler 		if (vhost->delay_init) {
6053848c7085STyrel Datwyler 			vhost->delay_init = 0;
6054848c7085STyrel Datwyler 			spin_unlock_irqrestore(vhost->host->host_lock, flags);
6055848c7085STyrel Datwyler 			ssleep(15);
6056848c7085STyrel Datwyler 			return;
6057848c7085STyrel Datwyler 		} else
6058848c7085STyrel Datwyler 			vhost->job_step(vhost);
6059848c7085STyrel Datwyler 		break;
6060848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_QUERY:
6061848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue)
6062848c7085STyrel Datwyler 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target);
60630a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
60640a3ab63eSTyrel Datwyler 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target);
6065848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY_TGTS);
6066848c7085STyrel Datwyler 		break;
6067848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_QUERY_TGTS:
6068848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
6069848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT) {
6070848c7085STyrel Datwyler 				tgt->job_step(tgt);
6071848c7085STyrel Datwyler 				break;
6072848c7085STyrel Datwyler 			}
6073848c7085STyrel Datwyler 		}
60740a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
60750a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT) {
60760a3ab63eSTyrel Datwyler 				tgt->job_step(tgt);
60770a3ab63eSTyrel Datwyler 				break;
60780a3ab63eSTyrel Datwyler 			}
60790a3ab63eSTyrel Datwyler 		}
6080848c7085STyrel Datwyler 
6081848c7085STyrel Datwyler 		if (!ibmvfc_dev_init_to_do(vhost))
6082848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL);
6083848c7085STyrel Datwyler 		break;
6084848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_DEL:
6085848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
6086848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
6087848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) {
6088848c7085STyrel Datwyler 				tgt->job_step(tgt);
6089848c7085STyrel Datwyler 				break;
6090848c7085STyrel Datwyler 			}
6091848c7085STyrel Datwyler 		}
60920a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
60930a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) {
60940a3ab63eSTyrel Datwyler 				tgt->job_step(tgt);
60950a3ab63eSTyrel Datwyler 				break;
60960a3ab63eSTyrel Datwyler 			}
60970a3ab63eSTyrel Datwyler 		}
6098848c7085STyrel Datwyler 
6099848c7085STyrel Datwyler 		if (ibmvfc_dev_logo_to_do(vhost)) {
6100848c7085STyrel Datwyler 			spin_unlock_irqrestore(vhost->host->host_lock, flags);
6101848c7085STyrel Datwyler 			return;
6102848c7085STyrel Datwyler 		}
6103848c7085STyrel Datwyler 
6104848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
6105848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
6106848c7085STyrel Datwyler 				tgt_dbg(tgt, "Deleting rport\n");
6107848c7085STyrel Datwyler 				rport = tgt->rport;
6108848c7085STyrel Datwyler 				tgt->rport = NULL;
6109848c7085STyrel Datwyler 				list_del(&tgt->queue);
6110848c7085STyrel Datwyler 				ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT);
6111848c7085STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
6112848c7085STyrel Datwyler 				if (rport)
6113848c7085STyrel Datwyler 					fc_remote_port_delete(rport);
6114848c7085STyrel Datwyler 				timer_delete_sync(&tgt->timer);
6115848c7085STyrel Datwyler 				kref_put(&tgt->kref, ibmvfc_release_tgt);
6116848c7085STyrel Datwyler 				return;
6117848c7085STyrel Datwyler 			} else if (tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) {
6118848c7085STyrel Datwyler 				tgt_dbg(tgt, "Deleting rport with I/O outstanding\n");
6119848c7085STyrel Datwyler 				rport = tgt->rport;
6120848c7085STyrel Datwyler 				tgt->rport = NULL;
6121848c7085STyrel Datwyler 				tgt->init_retries = 0;
6122848c7085STyrel Datwyler 				ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT);
6123848c7085STyrel Datwyler 
6124848c7085STyrel Datwyler 				/*
6125848c7085STyrel Datwyler 				 * If fast fail is enabled, we wait for it to fire and then clean up
6126848c7085STyrel Datwyler 				 * the old port, since we expect the fast fail timer to clean up the
6127848c7085STyrel Datwyler 				 * outstanding I/O faster than waiting for normal command timeouts.
6128848c7085STyrel Datwyler 				 * However, if fast fail is disabled, any I/O outstanding to the
6129848c7085STyrel Datwyler 				 * rport LUNs will stay outstanding indefinitely, since the EH handlers
6130848c7085STyrel Datwyler 				 * won't get invoked for I/O's timing out. If this is a NPIV failover
6131848c7085STyrel Datwyler 				 * scenario, the better alternative is to use the move login.
6132848c7085STyrel Datwyler 				 */
6133848c7085STyrel Datwyler 				if (rport && rport->fast_io_fail_tmo == -1)
6134848c7085STyrel Datwyler 					tgt->move_login = 1;
6135848c7085STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
6136848c7085STyrel Datwyler 				if (rport)
6137848c7085STyrel Datwyler 					fc_remote_port_delete(rport);
6138848c7085STyrel Datwyler 				return;
6139848c7085STyrel Datwyler 			}
6140848c7085STyrel Datwyler 		}
6141848c7085STyrel Datwyler 
6142696d1cc2STyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
6143696d1cc2STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
6144654fdae8SColin Ian King 				tgt_dbg(tgt, "Deleting NVMe rport\n");
6145696d1cc2STyrel Datwyler 				nvme_rport = tgt->nvme_remote_port;
6146696d1cc2STyrel Datwyler 				list_del(&tgt->queue);
6147696d1cc2STyrel Datwyler 				ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT);
6148696d1cc2STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
6149696d1cc2STyrel Datwyler 				if (nvme_rport)
6150696d1cc2STyrel Datwyler 					ibmvfc_nvme_unregister_remoteport(tgt);
6151696d1cc2STyrel Datwyler 				timer_delete_sync(&tgt->timer);
6152696d1cc2STyrel Datwyler 				kref_put(&tgt->kref, ibmvfc_release_tgt);
6153696d1cc2STyrel Datwyler 				return;
6154*b79b88b6SNathan Chancellor 			} else if (tgt->action == IBMVFC_TGT_ACTION_DEL_AND_LOGOUT_RPORT) {
6155696d1cc2STyrel Datwyler 				tgt_dbg(tgt, "Deleting NVMe rport with outstanding I/O\n");
6156696d1cc2STyrel Datwyler 				nvme_rport = tgt->nvme_remote_port;
6157696d1cc2STyrel Datwyler 				ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT);
6158696d1cc2STyrel Datwyler 				tgt->init_retries = 0;
6159696d1cc2STyrel Datwyler 				spin_unlock_irqrestore(vhost->host->host_lock, flags);
6160696d1cc2STyrel Datwyler 				if (nvme_rport)
6161696d1cc2STyrel Datwyler 					ibmvfc_nvme_unregister_remoteport(tgt);
6162696d1cc2STyrel Datwyler 				return;
6163696d1cc2STyrel Datwyler 			}
6164696d1cc2STyrel Datwyler 		}
6165696d1cc2STyrel Datwyler 
6166848c7085STyrel Datwyler 		if (vhost->state == IBMVFC_INITIALIZING) {
6167848c7085STyrel Datwyler 			if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) {
6168848c7085STyrel Datwyler 				if (vhost->reinit) {
6169848c7085STyrel Datwyler 					vhost->reinit = 0;
6170848c7085STyrel Datwyler 					scsi_block_requests(vhost->host);
6171848c7085STyrel Datwyler 					ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
6172848c7085STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6173848c7085STyrel Datwyler 				} else {
6174848c7085STyrel Datwyler 					ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
6175848c7085STyrel Datwyler 					ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
6176848c7085STyrel Datwyler 					wake_up(&vhost->init_wait_q);
6177848c7085STyrel Datwyler 					schedule_work(&vhost->rport_add_work_q);
6178848c7085STyrel Datwyler 					vhost->init_retries = 0;
6179848c7085STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6180848c7085STyrel Datwyler 					scsi_unblock_requests(vhost->host);
6181848c7085STyrel Datwyler 				}
6182848c7085STyrel Datwyler 
6183848c7085STyrel Datwyler 				return;
6184848c7085STyrel Datwyler 			} else {
6185848c7085STyrel Datwyler 				ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
6186848c7085STyrel Datwyler 				vhost->job_step = ibmvfc_discover_targets;
6187848c7085STyrel Datwyler 			}
6188848c7085STyrel Datwyler 		} else {
6189848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
6190848c7085STyrel Datwyler 			spin_unlock_irqrestore(vhost->host->host_lock, flags);
6191848c7085STyrel Datwyler 			scsi_unblock_requests(vhost->host);
6192848c7085STyrel Datwyler 			wake_up(&vhost->init_wait_q);
6193848c7085STyrel Datwyler 			return;
6194848c7085STyrel Datwyler 		}
6195848c7085STyrel Datwyler 		break;
6196848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_ALLOC_TGTS:
6197848c7085STyrel Datwyler 		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_INIT);
6198848c7085STyrel Datwyler 		spin_unlock_irqrestore(vhost->host->host_lock, flags);
6199848c7085STyrel Datwyler 		ibmvfc_alloc_targets(vhost);
6200848c7085STyrel Datwyler 		spin_lock_irqsave(vhost->host->host_lock, flags);
6201848c7085STyrel Datwyler 		break;
6202848c7085STyrel Datwyler 	case IBMVFC_HOST_ACTION_TGT_INIT:
6203848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
6204848c7085STyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT) {
6205848c7085STyrel Datwyler 				tgt->job_step(tgt);
6206848c7085STyrel Datwyler 				break;
6207848c7085STyrel Datwyler 			}
6208848c7085STyrel Datwyler 		}
62090a3ab63eSTyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
62100a3ab63eSTyrel Datwyler 			if (tgt->action == IBMVFC_TGT_ACTION_INIT) {
62110a3ab63eSTyrel Datwyler 				tgt->job_step(tgt);
62120a3ab63eSTyrel Datwyler 				break;
62130a3ab63eSTyrel Datwyler 			}
62140a3ab63eSTyrel Datwyler 		}
6215848c7085STyrel Datwyler 
6216848c7085STyrel Datwyler 		if (!ibmvfc_dev_init_to_do(vhost))
6217848c7085STyrel Datwyler 			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED);
6218848c7085STyrel Datwyler 		break;
6219848c7085STyrel Datwyler 	default:
6220848c7085STyrel Datwyler 		break;
6221848c7085STyrel Datwyler 	}
6222848c7085STyrel Datwyler 
6223848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
6224848c7085STyrel Datwyler }
6225848c7085STyrel Datwyler 
6226848c7085STyrel Datwyler /**
6227848c7085STyrel Datwyler  * ibmvfc_work - Do task level work
6228848c7085STyrel Datwyler  * @data:		ibmvfc host struct
6229848c7085STyrel Datwyler  *
6230848c7085STyrel Datwyler  * Returns:
6231848c7085STyrel Datwyler  *	zero
6232848c7085STyrel Datwyler  **/
ibmvfc_work(void * data)6233848c7085STyrel Datwyler static int ibmvfc_work(void *data)
6234848c7085STyrel Datwyler {
6235848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = data;
6236848c7085STyrel Datwyler 	int rc;
6237848c7085STyrel Datwyler 
6238848c7085STyrel Datwyler 	set_user_nice(current, MIN_NICE);
6239848c7085STyrel Datwyler 
6240848c7085STyrel Datwyler 	while (1) {
6241848c7085STyrel Datwyler 		rc = wait_event_interruptible(vhost->work_wait_q,
6242848c7085STyrel Datwyler 					      ibmvfc_work_to_do(vhost));
6243848c7085STyrel Datwyler 
6244848c7085STyrel Datwyler 		BUG_ON(rc);
6245848c7085STyrel Datwyler 
6246848c7085STyrel Datwyler 		if (kthread_should_stop())
6247848c7085STyrel Datwyler 			break;
6248848c7085STyrel Datwyler 
6249848c7085STyrel Datwyler 		ibmvfc_do_work(vhost);
6250848c7085STyrel Datwyler 	}
6251848c7085STyrel Datwyler 
6252848c7085STyrel Datwyler 	ibmvfc_dbg(vhost, "ibmvfc kthread exiting...\n");
6253848c7085STyrel Datwyler 	return 0;
6254848c7085STyrel Datwyler }
6255848c7085STyrel Datwyler 
6256848c7085STyrel Datwyler /**
6257848c7085STyrel Datwyler  * ibmvfc_alloc_queue - Allocate queue
6258848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
6259848c7085STyrel Datwyler  * @queue:	ibmvfc queue to allocate
6260848c7085STyrel Datwyler  * @fmt:	queue format to allocate
6261848c7085STyrel Datwyler  *
6262848c7085STyrel Datwyler  * Returns:
6263848c7085STyrel Datwyler  *	0 on success / non-zero on failure
6264848c7085STyrel Datwyler  **/
ibmvfc_alloc_queue(struct ibmvfc_host * vhost,struct ibmvfc_queue * queue,enum ibmvfc_msg_fmt fmt)6265848c7085STyrel Datwyler static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost,
6266848c7085STyrel Datwyler 			      struct ibmvfc_queue *queue,
6267848c7085STyrel Datwyler 			      enum ibmvfc_msg_fmt fmt)
6268848c7085STyrel Datwyler {
6269848c7085STyrel Datwyler 	struct device *dev = vhost->dev;
6270848c7085STyrel Datwyler 	size_t fmt_size;
6271848c7085STyrel Datwyler 
6272848c7085STyrel Datwyler 	ENTER;
6273848c7085STyrel Datwyler 	spin_lock_init(&queue->_lock);
6274848c7085STyrel Datwyler 	queue->q_lock = &queue->_lock;
6275848c7085STyrel Datwyler 
6276848c7085STyrel Datwyler 	switch (fmt) {
6277848c7085STyrel Datwyler 	case IBMVFC_CRQ_FMT:
6278848c7085STyrel Datwyler 		fmt_size = sizeof(*queue->msgs.crq);
6279848c7085STyrel Datwyler 		queue->total_depth = scsi_qdepth + IBMVFC_NUM_INTERNAL_REQ;
6280848c7085STyrel Datwyler 		queue->evt_depth = scsi_qdepth;
6281848c7085STyrel Datwyler 		queue->reserved_depth = IBMVFC_NUM_INTERNAL_REQ;
6282848c7085STyrel Datwyler 		break;
6283848c7085STyrel Datwyler 	case IBMVFC_ASYNC_FMT:
6284848c7085STyrel Datwyler 		fmt_size = sizeof(*queue->msgs.async);
6285848c7085STyrel Datwyler 		break;
6286848c7085STyrel Datwyler 	case IBMVFC_SUB_CRQ_FMT:
6287848c7085STyrel Datwyler 		fmt_size = sizeof(*queue->msgs.scrq);
6288848c7085STyrel Datwyler 		/* We need one extra event for Cancel Commands */
6289848c7085STyrel Datwyler 		queue->total_depth = scsi_qdepth + IBMVFC_NUM_INTERNAL_SUBQ_REQ;
6290848c7085STyrel Datwyler 		queue->evt_depth = scsi_qdepth;
6291848c7085STyrel Datwyler 		queue->reserved_depth = IBMVFC_NUM_INTERNAL_SUBQ_REQ;
6292848c7085STyrel Datwyler 		break;
6293848c7085STyrel Datwyler 	default:
6294848c7085STyrel Datwyler 		dev_warn(dev, "Unknown command/response queue message format: %d\n", fmt);
6295848c7085STyrel Datwyler 		return -EINVAL;
6296848c7085STyrel Datwyler 	}
6297848c7085STyrel Datwyler 
6298848c7085STyrel Datwyler 	queue->fmt = fmt;
6299848c7085STyrel Datwyler 	if (ibmvfc_init_event_pool(vhost, queue)) {
6300848c7085STyrel Datwyler 		dev_err(dev, "Couldn't initialize event pool.\n");
6301848c7085STyrel Datwyler 		return -ENOMEM;
6302848c7085STyrel Datwyler 	}
6303848c7085STyrel Datwyler 
6304848c7085STyrel Datwyler 	queue->msgs.handle = (void *)get_zeroed_page(GFP_KERNEL);
6305848c7085STyrel Datwyler 	if (!queue->msgs.handle)
6306848c7085STyrel Datwyler 		return -ENOMEM;
6307848c7085STyrel Datwyler 
6308848c7085STyrel Datwyler 	queue->msg_token = dma_map_single(dev, queue->msgs.handle, PAGE_SIZE,
6309848c7085STyrel Datwyler 					  DMA_BIDIRECTIONAL);
6310848c7085STyrel Datwyler 
6311848c7085STyrel Datwyler 	if (dma_mapping_error(dev, queue->msg_token)) {
6312848c7085STyrel Datwyler 		free_page((unsigned long)queue->msgs.handle);
6313848c7085STyrel Datwyler 		queue->msgs.handle = NULL;
6314848c7085STyrel Datwyler 		return -ENOMEM;
6315848c7085STyrel Datwyler 	}
6316848c7085STyrel Datwyler 
6317848c7085STyrel Datwyler 	queue->cur = 0;
6318848c7085STyrel Datwyler 	queue->size = PAGE_SIZE / fmt_size;
6319848c7085STyrel Datwyler 
6320848c7085STyrel Datwyler 	queue->vhost = vhost;
6321848c7085STyrel Datwyler 	return 0;
6322848c7085STyrel Datwyler }
6323848c7085STyrel Datwyler 
6324848c7085STyrel Datwyler /**
6325848c7085STyrel Datwyler  * ibmvfc_init_crq - Initializes and registers CRQ with hypervisor
6326848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
6327848c7085STyrel Datwyler  *
6328848c7085STyrel Datwyler  * Allocates a page for messages, maps it for dma, and registers
6329848c7085STyrel Datwyler  * the crq with the hypervisor.
6330848c7085STyrel Datwyler  *
6331848c7085STyrel Datwyler  * Return value:
6332848c7085STyrel Datwyler  *	zero on success / other on failure
6333848c7085STyrel Datwyler  **/
ibmvfc_init_crq(struct ibmvfc_host * vhost)6334848c7085STyrel Datwyler static int ibmvfc_init_crq(struct ibmvfc_host *vhost)
6335848c7085STyrel Datwyler {
6336848c7085STyrel Datwyler 	int rc, retrc = -ENOMEM;
6337848c7085STyrel Datwyler 	struct device *dev = vhost->dev;
6338848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(dev);
6339848c7085STyrel Datwyler 	struct ibmvfc_queue *crq = &vhost->crq;
6340848c7085STyrel Datwyler 
6341848c7085STyrel Datwyler 	ENTER;
6342848c7085STyrel Datwyler 	if (ibmvfc_alloc_queue(vhost, crq, IBMVFC_CRQ_FMT))
6343848c7085STyrel Datwyler 		return -ENOMEM;
6344848c7085STyrel Datwyler 
6345848c7085STyrel Datwyler 	retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
6346848c7085STyrel Datwyler 					crq->msg_token, PAGE_SIZE);
6347848c7085STyrel Datwyler 
6348848c7085STyrel Datwyler 	if (rc == H_RESOURCE)
6349848c7085STyrel Datwyler 		/* maybe kexecing and resource is busy. try a reset */
6350848c7085STyrel Datwyler 		retrc = rc = ibmvfc_reset_crq(vhost);
6351848c7085STyrel Datwyler 
6352848c7085STyrel Datwyler 	if (rc == H_CLOSED)
6353848c7085STyrel Datwyler 		dev_warn(dev, "Partner adapter not ready\n");
6354848c7085STyrel Datwyler 	else if (rc) {
6355848c7085STyrel Datwyler 		dev_warn(dev, "Error %d opening adapter\n", rc);
6356848c7085STyrel Datwyler 		goto reg_crq_failed;
6357848c7085STyrel Datwyler 	}
6358848c7085STyrel Datwyler 
6359848c7085STyrel Datwyler 	retrc = 0;
6360848c7085STyrel Datwyler 
6361848c7085STyrel Datwyler 	tasklet_init(&vhost->tasklet, (void *)ibmvfc_tasklet, (unsigned long)vhost);
6362848c7085STyrel Datwyler 
6363848c7085STyrel Datwyler 	if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) {
6364848c7085STyrel Datwyler 		dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc);
6365848c7085STyrel Datwyler 		goto req_irq_failed;
6366848c7085STyrel Datwyler 	}
6367848c7085STyrel Datwyler 
6368848c7085STyrel Datwyler 	if ((rc = vio_enable_interrupts(vdev))) {
6369848c7085STyrel Datwyler 		dev_err(dev, "Error %d enabling interrupts\n", rc);
6370848c7085STyrel Datwyler 		goto req_irq_failed;
6371848c7085STyrel Datwyler 	}
6372848c7085STyrel Datwyler 
6373848c7085STyrel Datwyler 	LEAVE;
6374848c7085STyrel Datwyler 	return retrc;
6375848c7085STyrel Datwyler 
6376848c7085STyrel Datwyler req_irq_failed:
6377848c7085STyrel Datwyler 	tasklet_kill(&vhost->tasklet);
6378848c7085STyrel Datwyler 	do {
6379848c7085STyrel Datwyler 		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
6380848c7085STyrel Datwyler 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
6381848c7085STyrel Datwyler reg_crq_failed:
6382848c7085STyrel Datwyler 	ibmvfc_free_queue(vhost, crq);
6383848c7085STyrel Datwyler 	return retrc;
6384848c7085STyrel Datwyler }
6385848c7085STyrel Datwyler 
ibmvfc_register_channel(struct ibmvfc_host * vhost,struct ibmvfc_channels * channels,int index)6386848c7085STyrel Datwyler static int ibmvfc_register_channel(struct ibmvfc_host *vhost,
6387848c7085STyrel Datwyler 				   struct ibmvfc_channels *channels,
6388848c7085STyrel Datwyler 				   int index)
6389848c7085STyrel Datwyler {
6390848c7085STyrel Datwyler 	struct device *dev = vhost->dev;
6391848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(dev);
6392848c7085STyrel Datwyler 	struct ibmvfc_queue *scrq = &channels->scrqs[index];
6393848c7085STyrel Datwyler 	int rc = -ENOMEM;
6394848c7085STyrel Datwyler 
6395848c7085STyrel Datwyler 	ENTER;
6396848c7085STyrel Datwyler 
6397848c7085STyrel Datwyler 	rc = h_reg_sub_crq(vdev->unit_address, scrq->msg_token, PAGE_SIZE,
6398848c7085STyrel Datwyler 			   &scrq->cookie, &scrq->hw_irq);
6399848c7085STyrel Datwyler 
6400848c7085STyrel Datwyler 	/* H_CLOSED indicates successful register, but no CRQ partner */
6401848c7085STyrel Datwyler 	if (rc && rc != H_CLOSED) {
6402848c7085STyrel Datwyler 		dev_warn(dev, "Error registering sub-crq: %d\n", rc);
6403848c7085STyrel Datwyler 		if (rc == H_PARAMETER)
6404848c7085STyrel Datwyler 			dev_warn_once(dev, "Firmware may not support MQ\n");
6405848c7085STyrel Datwyler 		goto reg_failed;
6406848c7085STyrel Datwyler 	}
6407848c7085STyrel Datwyler 
6408848c7085STyrel Datwyler 	scrq->irq = irq_create_mapping(NULL, scrq->hw_irq);
6409848c7085STyrel Datwyler 
6410848c7085STyrel Datwyler 	if (!scrq->irq) {
6411848c7085STyrel Datwyler 		rc = -EINVAL;
6412848c7085STyrel Datwyler 		dev_err(dev, "Error mapping sub-crq[%d] irq\n", index);
6413848c7085STyrel Datwyler 		goto irq_failed;
6414848c7085STyrel Datwyler 	}
6415848c7085STyrel Datwyler 
6416848c7085STyrel Datwyler 	switch (channels->protocol) {
6417848c7085STyrel Datwyler 	case IBMVFC_PROTO_SCSI:
6418848c7085STyrel Datwyler 		snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d",
6419848c7085STyrel Datwyler 			 vdev->unit_address, index);
6420848c7085STyrel Datwyler 		scrq->handler = ibmvfc_interrupt_mq;
6421848c7085STyrel Datwyler 		break;
6422848c7085STyrel Datwyler 	case IBMVFC_PROTO_NVME:
6423848c7085STyrel Datwyler 		snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%d",
6424848c7085STyrel Datwyler 			 vdev->unit_address, index);
6425848c7085STyrel Datwyler 		scrq->handler = ibmvfc_interrupt_mq;
6426848c7085STyrel Datwyler 		break;
6427848c7085STyrel Datwyler 	default:
6428848c7085STyrel Datwyler 		dev_err(dev, "Unknown channel protocol (%d)\n",
6429848c7085STyrel Datwyler 			channels->protocol);
6430848c7085STyrel Datwyler 		goto irq_failed;
6431848c7085STyrel Datwyler 	}
6432848c7085STyrel Datwyler 
6433848c7085STyrel Datwyler 	rc = request_irq(scrq->irq, scrq->handler, 0, scrq->name, scrq);
6434848c7085STyrel Datwyler 
6435848c7085STyrel Datwyler 	if (rc) {
6436848c7085STyrel Datwyler 		dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index);
6437848c7085STyrel Datwyler 		irq_dispose_mapping(scrq->irq);
6438848c7085STyrel Datwyler 		goto irq_failed;
6439848c7085STyrel Datwyler 	}
6440848c7085STyrel Datwyler 
6441848c7085STyrel Datwyler 	scrq->hwq_id = index;
6442848c7085STyrel Datwyler 
6443848c7085STyrel Datwyler 	LEAVE;
6444848c7085STyrel Datwyler 	return 0;
6445848c7085STyrel Datwyler 
6446848c7085STyrel Datwyler irq_failed:
6447848c7085STyrel Datwyler 	do {
6448848c7085STyrel Datwyler 		rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cookie);
6449848c7085STyrel Datwyler 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
6450848c7085STyrel Datwyler reg_failed:
6451848c7085STyrel Datwyler 	LEAVE;
6452848c7085STyrel Datwyler 	return rc;
6453848c7085STyrel Datwyler }
6454848c7085STyrel Datwyler 
ibmvfc_deregister_channel(struct ibmvfc_host * vhost,struct ibmvfc_channels * channels,int index)6455848c7085STyrel Datwyler static void ibmvfc_deregister_channel(struct ibmvfc_host *vhost,
6456848c7085STyrel Datwyler 				      struct ibmvfc_channels *channels,
6457848c7085STyrel Datwyler 				      int index)
6458848c7085STyrel Datwyler {
6459848c7085STyrel Datwyler 	struct device *dev = vhost->dev;
6460848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(dev);
6461848c7085STyrel Datwyler 	struct ibmvfc_queue *scrq = &channels->scrqs[index];
6462848c7085STyrel Datwyler 	long rc;
6463848c7085STyrel Datwyler 
6464848c7085STyrel Datwyler 	ENTER;
6465848c7085STyrel Datwyler 
6466848c7085STyrel Datwyler 	free_irq(scrq->irq, scrq);
6467848c7085STyrel Datwyler 	irq_dispose_mapping(scrq->irq);
6468848c7085STyrel Datwyler 	scrq->irq = 0;
6469848c7085STyrel Datwyler 
6470848c7085STyrel Datwyler 	do {
6471848c7085STyrel Datwyler 		rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address,
6472848c7085STyrel Datwyler 					scrq->cookie);
6473848c7085STyrel Datwyler 	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
6474848c7085STyrel Datwyler 
6475848c7085STyrel Datwyler 	if (rc)
6476848c7085STyrel Datwyler 		dev_err(dev, "Failed to free sub-crq[%d]: rc=%ld\n", index, rc);
6477848c7085STyrel Datwyler 
6478848c7085STyrel Datwyler 	/* Clean out the queue */
6479848c7085STyrel Datwyler 	memset(scrq->msgs.crq, 0, PAGE_SIZE);
6480848c7085STyrel Datwyler 	scrq->cur = 0;
6481848c7085STyrel Datwyler 
6482848c7085STyrel Datwyler 	LEAVE;
6483848c7085STyrel Datwyler }
6484848c7085STyrel Datwyler 
ibmvfc_reg_sub_crqs(struct ibmvfc_host * vhost,struct ibmvfc_channels * channels)6485848c7085STyrel Datwyler static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *vhost,
6486848c7085STyrel Datwyler 				struct ibmvfc_channels *channels)
6487848c7085STyrel Datwyler {
6488848c7085STyrel Datwyler 	int i, j;
6489848c7085STyrel Datwyler 
6490848c7085STyrel Datwyler 	ENTER;
6491848c7085STyrel Datwyler 	if (!vhost->mq_enabled || !channels->scrqs)
6492848c7085STyrel Datwyler 		return;
6493848c7085STyrel Datwyler 
6494848c7085STyrel Datwyler 	for (i = 0; i < channels->max_queues; i++) {
6495848c7085STyrel Datwyler 		if (ibmvfc_register_channel(vhost, channels, i)) {
6496848c7085STyrel Datwyler 			for (j = i; j > 0; j--)
6497848c7085STyrel Datwyler 				ibmvfc_deregister_channel(vhost, channels, j - 1);
6498848c7085STyrel Datwyler 			vhost->do_enquiry = 0;
6499848c7085STyrel Datwyler 			return;
6500848c7085STyrel Datwyler 		}
6501848c7085STyrel Datwyler 	}
6502848c7085STyrel Datwyler 
6503848c7085STyrel Datwyler 	LEAVE;
6504848c7085STyrel Datwyler }
6505848c7085STyrel Datwyler 
ibmvfc_dereg_sub_crqs(struct ibmvfc_host * vhost,struct ibmvfc_channels * channels)6506848c7085STyrel Datwyler static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *vhost,
6507848c7085STyrel Datwyler 				  struct ibmvfc_channels *channels)
6508848c7085STyrel Datwyler {
6509848c7085STyrel Datwyler 	int i;
6510848c7085STyrel Datwyler 
6511848c7085STyrel Datwyler 	ENTER;
6512848c7085STyrel Datwyler 	if (!vhost->mq_enabled || !channels->scrqs)
6513848c7085STyrel Datwyler 		return;
6514848c7085STyrel Datwyler 
6515848c7085STyrel Datwyler 	for (i = 0; i < channels->max_queues; i++)
6516848c7085STyrel Datwyler 		ibmvfc_deregister_channel(vhost, channels, i);
6517848c7085STyrel Datwyler 
6518848c7085STyrel Datwyler 	LEAVE;
6519848c7085STyrel Datwyler }
6520848c7085STyrel Datwyler 
ibmvfc_alloc_channels(struct ibmvfc_host * vhost,struct ibmvfc_channels * channels)6521848c7085STyrel Datwyler static int ibmvfc_alloc_channels(struct ibmvfc_host *vhost,
6522848c7085STyrel Datwyler 				 struct ibmvfc_channels *channels)
6523848c7085STyrel Datwyler {
6524848c7085STyrel Datwyler 	struct ibmvfc_queue *scrq;
6525848c7085STyrel Datwyler 	int i, j;
6526848c7085STyrel Datwyler 	int rc = 0;
6527848c7085STyrel Datwyler 
6528848c7085STyrel Datwyler 	channels->scrqs = kzalloc_objs(*channels->scrqs, channels->max_queues);
6529848c7085STyrel Datwyler 	if (!channels->scrqs)
6530848c7085STyrel Datwyler 		return -ENOMEM;
6531848c7085STyrel Datwyler 
6532848c7085STyrel Datwyler 	for (i = 0; i < channels->max_queues; i++) {
6533848c7085STyrel Datwyler 		scrq = &channels->scrqs[i];
6534848c7085STyrel Datwyler 		rc = ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT);
6535848c7085STyrel Datwyler 		if (rc) {
6536848c7085STyrel Datwyler 			for (j = i; j > 0; j--) {
6537848c7085STyrel Datwyler 				scrq = &channels->scrqs[j - 1];
6538848c7085STyrel Datwyler 				ibmvfc_free_queue(vhost, scrq);
6539848c7085STyrel Datwyler 			}
6540848c7085STyrel Datwyler 			kfree(channels->scrqs);
6541848c7085STyrel Datwyler 			channels->scrqs = NULL;
6542848c7085STyrel Datwyler 			channels->active_queues = 0;
6543848c7085STyrel Datwyler 			return rc;
6544848c7085STyrel Datwyler 		}
6545848c7085STyrel Datwyler 	}
6546848c7085STyrel Datwyler 
6547848c7085STyrel Datwyler 	return rc;
6548848c7085STyrel Datwyler }
6549848c7085STyrel Datwyler 
ibmvfc_init_sub_crqs(struct ibmvfc_host * vhost)6550848c7085STyrel Datwyler static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)
6551848c7085STyrel Datwyler {
6552848c7085STyrel Datwyler 	ENTER;
6553848c7085STyrel Datwyler 	if (!vhost->mq_enabled)
6554848c7085STyrel Datwyler 		return;
6555848c7085STyrel Datwyler 
6556848c7085STyrel Datwyler 	if (ibmvfc_alloc_channels(vhost, &vhost->scsi_scrqs)) {
6557848c7085STyrel Datwyler 		vhost->do_enquiry = 0;
6558848c7085STyrel Datwyler 		vhost->mq_enabled = 0;
6559848c7085STyrel Datwyler 		return;
6560848c7085STyrel Datwyler 	}
6561848c7085STyrel Datwyler 
6562848c7085STyrel Datwyler 	ibmvfc_reg_sub_crqs(vhost, &vhost->scsi_scrqs);
6563848c7085STyrel Datwyler 
6564319f6545STyrel Datwyler 	if (vhost->nvme_enabled) {
6565319f6545STyrel Datwyler 		if (ibmvfc_alloc_channels(vhost, &vhost->nvme_scrqs))
6566319f6545STyrel Datwyler 			vhost->nvme_enabled = 0;
6567319f6545STyrel Datwyler 		else
6568319f6545STyrel Datwyler 			ibmvfc_reg_sub_crqs(vhost, &vhost->nvme_scrqs);
6569319f6545STyrel Datwyler 	}
6570319f6545STyrel Datwyler 
6571848c7085STyrel Datwyler 	LEAVE;
6572848c7085STyrel Datwyler }
6573848c7085STyrel Datwyler 
ibmvfc_release_channels(struct ibmvfc_host * vhost,struct ibmvfc_channels * channels)6574848c7085STyrel Datwyler static void ibmvfc_release_channels(struct ibmvfc_host *vhost,
6575848c7085STyrel Datwyler 				    struct ibmvfc_channels *channels)
6576848c7085STyrel Datwyler {
6577848c7085STyrel Datwyler 	struct ibmvfc_queue *scrq;
6578848c7085STyrel Datwyler 	int i;
6579848c7085STyrel Datwyler 
6580848c7085STyrel Datwyler 	if (channels->scrqs) {
6581848c7085STyrel Datwyler 		for (i = 0; i < channels->max_queues; i++) {
6582848c7085STyrel Datwyler 			scrq = &channels->scrqs[i];
6583848c7085STyrel Datwyler 			ibmvfc_free_queue(vhost, scrq);
6584848c7085STyrel Datwyler 		}
6585848c7085STyrel Datwyler 
6586848c7085STyrel Datwyler 		kfree(channels->scrqs);
6587848c7085STyrel Datwyler 		channels->scrqs = NULL;
6588848c7085STyrel Datwyler 		channels->active_queues = 0;
6589848c7085STyrel Datwyler 	}
6590848c7085STyrel Datwyler }
6591848c7085STyrel Datwyler 
ibmvfc_release_sub_crqs(struct ibmvfc_host * vhost)6592848c7085STyrel Datwyler static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost)
6593848c7085STyrel Datwyler {
6594848c7085STyrel Datwyler 	ENTER;
6595848c7085STyrel Datwyler 	if (!vhost->scsi_scrqs.scrqs)
6596848c7085STyrel Datwyler 		return;
6597848c7085STyrel Datwyler 
6598848c7085STyrel Datwyler 	ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs);
6599848c7085STyrel Datwyler 	ibmvfc_release_channels(vhost, &vhost->scsi_scrqs);
6600319f6545STyrel Datwyler 
6601319f6545STyrel Datwyler 	ibmvfc_dereg_sub_crqs(vhost, &vhost->nvme_scrqs);
6602319f6545STyrel Datwyler 	ibmvfc_release_channels(vhost, &vhost->nvme_scrqs);
6603848c7085STyrel Datwyler 	LEAVE;
6604848c7085STyrel Datwyler }
6605848c7085STyrel Datwyler 
ibmvfc_free_disc_buf(struct device * dev,struct ibmvfc_channels * channels)6606848c7085STyrel Datwyler static void ibmvfc_free_disc_buf(struct device *dev, struct ibmvfc_channels *channels)
6607848c7085STyrel Datwyler {
6608848c7085STyrel Datwyler 	dma_free_coherent(dev, channels->disc_buf_sz, channels->disc_buf,
6609848c7085STyrel Datwyler 			  channels->disc_buf_dma);
6610848c7085STyrel Datwyler }
6611848c7085STyrel Datwyler 
6612848c7085STyrel Datwyler /**
6613848c7085STyrel Datwyler  * ibmvfc_free_mem - Free memory for vhost
6614848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
6615848c7085STyrel Datwyler  *
6616848c7085STyrel Datwyler  * Return value:
6617848c7085STyrel Datwyler  * 	none
6618848c7085STyrel Datwyler  **/
ibmvfc_free_mem(struct ibmvfc_host * vhost)6619848c7085STyrel Datwyler static void ibmvfc_free_mem(struct ibmvfc_host *vhost)
6620848c7085STyrel Datwyler {
6621848c7085STyrel Datwyler 	struct ibmvfc_queue *async_q = &vhost->async_crq;
6622848c7085STyrel Datwyler 
6623848c7085STyrel Datwyler 	ENTER;
6624848c7085STyrel Datwyler 	mempool_destroy(vhost->tgt_pool);
6625848c7085STyrel Datwyler 	kfree(vhost->trace);
6626848c7085STyrel Datwyler 	ibmvfc_free_disc_buf(vhost->dev, &vhost->scsi_scrqs);
6627fe150862STyrel Datwyler 	ibmvfc_free_disc_buf(vhost->dev, &vhost->nvme_scrqs);
6628848c7085STyrel Datwyler 	dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf),
6629848c7085STyrel Datwyler 			  vhost->login_buf, vhost->login_buf_dma);
6630848c7085STyrel Datwyler 	dma_free_coherent(vhost->dev, sizeof(*vhost->channel_setup_buf),
6631848c7085STyrel Datwyler 			  vhost->channel_setup_buf, vhost->channel_setup_dma);
6632848c7085STyrel Datwyler 	dma_pool_destroy(vhost->sg_pool);
6633848c7085STyrel Datwyler 	ibmvfc_free_queue(vhost, async_q);
6634848c7085STyrel Datwyler 	LEAVE;
6635848c7085STyrel Datwyler }
6636848c7085STyrel Datwyler 
ibmvfc_alloc_disc_buf(struct device * dev,struct ibmvfc_channels * channels)6637848c7085STyrel Datwyler static int ibmvfc_alloc_disc_buf(struct device *dev, struct ibmvfc_channels *channels)
6638848c7085STyrel Datwyler {
6639848c7085STyrel Datwyler 	channels->disc_buf_sz = sizeof(*channels->disc_buf) * max_targets;
6640848c7085STyrel Datwyler 	channels->disc_buf = dma_alloc_coherent(dev, channels->disc_buf_sz,
6641848c7085STyrel Datwyler 					     &channels->disc_buf_dma, GFP_KERNEL);
6642848c7085STyrel Datwyler 
6643848c7085STyrel Datwyler 	if (!channels->disc_buf) {
6644848c7085STyrel Datwyler 		dev_err(dev, "Couldn't allocate %s Discover Targets buffer\n",
6645848c7085STyrel Datwyler 			(channels->protocol == IBMVFC_PROTO_SCSI) ? "SCSI" : "NVMe");
6646848c7085STyrel Datwyler 		return -ENOMEM;
6647848c7085STyrel Datwyler 	}
6648848c7085STyrel Datwyler 
6649848c7085STyrel Datwyler 	return 0;
6650848c7085STyrel Datwyler }
6651848c7085STyrel Datwyler 
6652848c7085STyrel Datwyler /**
6653848c7085STyrel Datwyler  * ibmvfc_alloc_mem - Allocate memory for vhost
6654848c7085STyrel Datwyler  * @vhost:	ibmvfc host struct
6655848c7085STyrel Datwyler  *
6656848c7085STyrel Datwyler  * Return value:
6657848c7085STyrel Datwyler  * 	0 on success / non-zero on failure
6658848c7085STyrel Datwyler  **/
ibmvfc_alloc_mem(struct ibmvfc_host * vhost)6659848c7085STyrel Datwyler static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost)
6660848c7085STyrel Datwyler {
6661848c7085STyrel Datwyler 	struct ibmvfc_queue *async_q = &vhost->async_crq;
6662848c7085STyrel Datwyler 	struct device *dev = vhost->dev;
6663848c7085STyrel Datwyler 
6664848c7085STyrel Datwyler 	ENTER;
6665848c7085STyrel Datwyler 	if (ibmvfc_alloc_queue(vhost, async_q, IBMVFC_ASYNC_FMT)) {
6666848c7085STyrel Datwyler 		dev_err(dev, "Couldn't allocate/map async queue.\n");
6667848c7085STyrel Datwyler 		goto nomem;
6668848c7085STyrel Datwyler 	}
6669848c7085STyrel Datwyler 
6670848c7085STyrel Datwyler 	vhost->sg_pool = dma_pool_create(IBMVFC_NAME, dev,
6671848c7085STyrel Datwyler 					 SG_ALL * sizeof(struct srp_direct_buf),
6672848c7085STyrel Datwyler 					 sizeof(struct srp_direct_buf), 0);
6673848c7085STyrel Datwyler 
6674848c7085STyrel Datwyler 	if (!vhost->sg_pool) {
6675848c7085STyrel Datwyler 		dev_err(dev, "Failed to allocate sg pool\n");
6676848c7085STyrel Datwyler 		goto unmap_async_crq;
6677848c7085STyrel Datwyler 	}
6678848c7085STyrel Datwyler 
6679848c7085STyrel Datwyler 	vhost->login_buf = dma_alloc_coherent(dev, sizeof(*vhost->login_buf),
6680848c7085STyrel Datwyler 					      &vhost->login_buf_dma, GFP_KERNEL);
6681848c7085STyrel Datwyler 
6682848c7085STyrel Datwyler 	if (!vhost->login_buf) {
6683848c7085STyrel Datwyler 		dev_err(dev, "Couldn't allocate NPIV login buffer\n");
6684848c7085STyrel Datwyler 		goto free_sg_pool;
6685848c7085STyrel Datwyler 	}
6686848c7085STyrel Datwyler 
6687848c7085STyrel Datwyler 	if (ibmvfc_alloc_disc_buf(dev, &vhost->scsi_scrqs))
6688848c7085STyrel Datwyler 		goto free_login_buffer;
6689848c7085STyrel Datwyler 
6690fe150862STyrel Datwyler 	if (ibmvfc_alloc_disc_buf(dev, &vhost->nvme_scrqs))
6691fe150862STyrel Datwyler 		goto free_scsi_disc_buffer;
6692fe150862STyrel Datwyler 
6693848c7085STyrel Datwyler 	vhost->trace = kzalloc_objs(struct ibmvfc_trace_entry,
6694848c7085STyrel Datwyler 				    IBMVFC_NUM_TRACE_ENTRIES);
6695848c7085STyrel Datwyler 	atomic_set(&vhost->trace_index, -1);
6696848c7085STyrel Datwyler 
6697848c7085STyrel Datwyler 	if (!vhost->trace)
6698fe150862STyrel Datwyler 		goto free_nvme_disc_buffer;
6699848c7085STyrel Datwyler 
6700848c7085STyrel Datwyler 	vhost->tgt_pool = mempool_create_kmalloc_pool(IBMVFC_TGT_MEMPOOL_SZ,
6701848c7085STyrel Datwyler 						      sizeof(struct ibmvfc_target));
6702848c7085STyrel Datwyler 
6703848c7085STyrel Datwyler 	if (!vhost->tgt_pool) {
6704848c7085STyrel Datwyler 		dev_err(dev, "Couldn't allocate target memory pool\n");
6705848c7085STyrel Datwyler 		goto free_trace;
6706848c7085STyrel Datwyler 	}
6707848c7085STyrel Datwyler 
6708848c7085STyrel Datwyler 	vhost->channel_setup_buf = dma_alloc_coherent(dev, sizeof(*vhost->channel_setup_buf),
6709848c7085STyrel Datwyler 						      &vhost->channel_setup_dma,
6710848c7085STyrel Datwyler 						      GFP_KERNEL);
6711848c7085STyrel Datwyler 
6712848c7085STyrel Datwyler 	if (!vhost->channel_setup_buf) {
6713848c7085STyrel Datwyler 		dev_err(dev, "Couldn't allocate Channel Setup buffer\n");
6714848c7085STyrel Datwyler 		goto free_tgt_pool;
6715848c7085STyrel Datwyler 	}
6716848c7085STyrel Datwyler 
6717848c7085STyrel Datwyler 	LEAVE;
6718848c7085STyrel Datwyler 	return 0;
6719848c7085STyrel Datwyler 
6720848c7085STyrel Datwyler free_tgt_pool:
6721848c7085STyrel Datwyler 	mempool_destroy(vhost->tgt_pool);
6722848c7085STyrel Datwyler free_trace:
6723848c7085STyrel Datwyler 	kfree(vhost->trace);
6724fe150862STyrel Datwyler free_nvme_disc_buffer:
6725fe150862STyrel Datwyler 	ibmvfc_free_disc_buf(dev, &vhost->nvme_scrqs);
6726848c7085STyrel Datwyler free_scsi_disc_buffer:
6727848c7085STyrel Datwyler 	ibmvfc_free_disc_buf(dev, &vhost->scsi_scrqs);
6728848c7085STyrel Datwyler free_login_buffer:
6729848c7085STyrel Datwyler 	dma_free_coherent(dev, sizeof(*vhost->login_buf),
6730848c7085STyrel Datwyler 			  vhost->login_buf, vhost->login_buf_dma);
6731848c7085STyrel Datwyler free_sg_pool:
6732848c7085STyrel Datwyler 	dma_pool_destroy(vhost->sg_pool);
6733848c7085STyrel Datwyler unmap_async_crq:
6734848c7085STyrel Datwyler 	ibmvfc_free_queue(vhost, async_q);
6735848c7085STyrel Datwyler nomem:
6736848c7085STyrel Datwyler 	LEAVE;
6737848c7085STyrel Datwyler 	return -ENOMEM;
6738848c7085STyrel Datwyler }
6739848c7085STyrel Datwyler 
6740848c7085STyrel Datwyler /**
6741848c7085STyrel Datwyler  * ibmvfc_rport_add_thread - Worker thread for rport adds
6742848c7085STyrel Datwyler  * @work:	work struct
6743848c7085STyrel Datwyler  *
6744848c7085STyrel Datwyler  **/
ibmvfc_rport_add_thread(struct work_struct * work)6745848c7085STyrel Datwyler static void ibmvfc_rport_add_thread(struct work_struct *work)
6746848c7085STyrel Datwyler {
6747848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host,
6748848c7085STyrel Datwyler 						 rport_add_work_q);
6749848c7085STyrel Datwyler 	struct ibmvfc_target *tgt;
6750848c7085STyrel Datwyler 	struct fc_rport *rport;
6751696d1cc2STyrel Datwyler 	struct nvme_fc_remote_port *nvme_rport;
6752848c7085STyrel Datwyler 	unsigned long flags;
6753848c7085STyrel Datwyler 	int did_work;
6754848c7085STyrel Datwyler 
6755848c7085STyrel Datwyler 	ENTER;
6756848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
6757848c7085STyrel Datwyler 	do {
6758848c7085STyrel Datwyler 		did_work = 0;
6759848c7085STyrel Datwyler 		if (vhost->state != IBMVFC_ACTIVE)
6760848c7085STyrel Datwyler 			break;
6761848c7085STyrel Datwyler 
6762848c7085STyrel Datwyler 		list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) {
6763848c7085STyrel Datwyler 			if (tgt->add_rport) {
6764848c7085STyrel Datwyler 				did_work = 1;
6765848c7085STyrel Datwyler 				tgt->add_rport = 0;
6766848c7085STyrel Datwyler 				kref_get(&tgt->kref);
6767848c7085STyrel Datwyler 				rport = tgt->rport;
6768848c7085STyrel Datwyler 				if (!rport) {
6769848c7085STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6770848c7085STyrel Datwyler 					ibmvfc_tgt_add_rport(tgt);
6771848c7085STyrel Datwyler 				} else if (get_device(&rport->dev)) {
6772848c7085STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6773848c7085STyrel Datwyler 					tgt_dbg(tgt, "Setting rport roles\n");
6774848c7085STyrel Datwyler 					fc_remote_port_rolechg(rport, tgt->ids.roles);
6775848c7085STyrel Datwyler 					put_device(&rport->dev);
6776848c7085STyrel Datwyler 				} else {
6777848c7085STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6778848c7085STyrel Datwyler 				}
6779848c7085STyrel Datwyler 
6780848c7085STyrel Datwyler 				kref_put(&tgt->kref, ibmvfc_release_tgt);
6781848c7085STyrel Datwyler 				spin_lock_irqsave(vhost->host->host_lock, flags);
6782848c7085STyrel Datwyler 				break;
6783848c7085STyrel Datwyler 			}
6784848c7085STyrel Datwyler 		}
6785696d1cc2STyrel Datwyler 
6786696d1cc2STyrel Datwyler 		list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) {
6787696d1cc2STyrel Datwyler 			if (tgt->add_rport) {
6788696d1cc2STyrel Datwyler 				did_work = 1;
6789696d1cc2STyrel Datwyler 				tgt->add_rport = 0;
6790696d1cc2STyrel Datwyler 				kref_get(&tgt->kref);
6791696d1cc2STyrel Datwyler 				nvme_rport = tgt->nvme_remote_port;
6792696d1cc2STyrel Datwyler 				if (!nvme_rport) {
6793696d1cc2STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6794696d1cc2STyrel Datwyler 					ibmvfc_tgt_add_nvme_rport(tgt);
6795696d1cc2STyrel Datwyler 				} else {
6796696d1cc2STyrel Datwyler 					spin_unlock_irqrestore(vhost->host->host_lock, flags);
6797696d1cc2STyrel Datwyler 					if (IS_ENABLED(CONFIG_NVME_FC))
6798696d1cc2STyrel Datwyler 						nvme_fc_rescan_remoteport(nvme_rport);
6799696d1cc2STyrel Datwyler 				}
6800696d1cc2STyrel Datwyler 
6801696d1cc2STyrel Datwyler 				kref_put(&tgt->kref, ibmvfc_release_tgt);
6802696d1cc2STyrel Datwyler 				spin_lock_irqsave(vhost->host->host_lock, flags);
6803696d1cc2STyrel Datwyler 				break;
6804696d1cc2STyrel Datwyler 			}
6805696d1cc2STyrel Datwyler 		}
6806848c7085STyrel Datwyler 	} while (did_work);
6807848c7085STyrel Datwyler 
6808848c7085STyrel Datwyler 	if (vhost->state == IBMVFC_ACTIVE)
6809848c7085STyrel Datwyler 		vhost->scan_complete = 1;
6810848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
6811848c7085STyrel Datwyler 	LEAVE;
6812848c7085STyrel Datwyler }
6813848c7085STyrel Datwyler 
6814848c7085STyrel Datwyler /**
6815848c7085STyrel Datwyler  * ibmvfc_probe - Adapter hot plug add entry point
6816848c7085STyrel Datwyler  * @vdev:	vio device struct
6817848c7085STyrel Datwyler  * @id:	vio device id struct
6818848c7085STyrel Datwyler  *
6819848c7085STyrel Datwyler  * Return value:
6820848c7085STyrel Datwyler  * 	0 on success / non-zero on failure
6821848c7085STyrel Datwyler  **/
ibmvfc_probe(struct vio_dev * vdev,const struct vio_device_id * id)6822848c7085STyrel Datwyler static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
6823848c7085STyrel Datwyler {
6824848c7085STyrel Datwyler 	struct ibmvfc_host *vhost;
6825848c7085STyrel Datwyler 	struct Scsi_Host *shost;
6826848c7085STyrel Datwyler 	struct device *dev = &vdev->dev;
6827848c7085STyrel Datwyler 	int rc = -ENOMEM;
6828848c7085STyrel Datwyler 	unsigned int online_cpus = num_online_cpus();
6829018fc396STyrel Datwyler 	unsigned int max_scsi_queues = min_t(unsigned int, IBMVFC_MAX_SCSI_QUEUES, online_cpus);
6830018fc396STyrel Datwyler 	unsigned int max_nvme_queues = min_t(unsigned int, IBMVFC_MAX_NVME_QUEUES, online_cpus);
6831848c7085STyrel Datwyler 
6832848c7085STyrel Datwyler 	ENTER;
6833848c7085STyrel Datwyler 	shost = scsi_host_alloc(&driver_template, sizeof(*vhost));
6834848c7085STyrel Datwyler 	if (!shost) {
6835848c7085STyrel Datwyler 		dev_err(dev, "Couldn't allocate host data\n");
6836848c7085STyrel Datwyler 		goto out;
6837848c7085STyrel Datwyler 	}
6838848c7085STyrel Datwyler 
6839848c7085STyrel Datwyler 	shost->transportt = ibmvfc_transport_template;
6840848c7085STyrel Datwyler 	shost->can_queue = scsi_qdepth;
6841848c7085STyrel Datwyler 	shost->max_lun = max_lun;
6842848c7085STyrel Datwyler 	shost->max_id = max_targets;
6843848c7085STyrel Datwyler 	shost->max_sectors = max_sectors;
6844848c7085STyrel Datwyler 	shost->max_cmd_len = IBMVFC_MAX_CDB_LEN;
6845848c7085STyrel Datwyler 	shost->unique_id = shost->host_no;
6846848c7085STyrel Datwyler 	shost->nr_hw_queues = mq_enabled ? min(max_scsi_queues, nr_scsi_hw_queues) : 1;
6847848c7085STyrel Datwyler 
6848848c7085STyrel Datwyler 	vhost = shost_priv(shost);
6849848c7085STyrel Datwyler 	INIT_LIST_HEAD(&vhost->scsi_scrqs.targets);
6850018fc396STyrel Datwyler 	INIT_LIST_HEAD(&vhost->nvme_scrqs.targets);
6851848c7085STyrel Datwyler 	INIT_LIST_HEAD(&vhost->purge);
6852848c7085STyrel Datwyler 	sprintf(vhost->name, IBMVFC_NAME);
6853848c7085STyrel Datwyler 	vhost->host = shost;
6854848c7085STyrel Datwyler 	vhost->dev = dev;
6855848c7085STyrel Datwyler 	vhost->partition_number = -1;
6856848c7085STyrel Datwyler 	vhost->log_level = log_level;
6857848c7085STyrel Datwyler 	vhost->task_set = 1;
6858848c7085STyrel Datwyler 
6859848c7085STyrel Datwyler 	vhost->mq_enabled = mq_enabled;
6860848c7085STyrel Datwyler 	vhost->scsi_scrqs.desired_queues = min(shost->nr_hw_queues, nr_scsi_channels);
6861848c7085STyrel Datwyler 	vhost->scsi_scrqs.max_queues = shost->nr_hw_queues;
6862848c7085STyrel Datwyler 	vhost->scsi_scrqs.protocol = IBMVFC_PROTO_SCSI;
6863848c7085STyrel Datwyler 	vhost->using_channels = 0;
6864848c7085STyrel Datwyler 	vhost->do_enquiry = 1;
6865018fc396STyrel Datwyler 	vhost->nvme_enabled = mq_enabled ? nvme_enabled : 0;
6866018fc396STyrel Datwyler 	vhost->nvme_scrqs.desired_queues = min(max_nvme_queues, nr_nvme_channels);
6867018fc396STyrel Datwyler 	vhost->nvme_scrqs.max_queues = max_nvme_queues;
6868018fc396STyrel Datwyler 	vhost->nvme_scrqs.protocol = IBMVFC_PROTO_NVME;
6869848c7085STyrel Datwyler 	vhost->scan_timeout = 0;
6870848c7085STyrel Datwyler 
6871848c7085STyrel Datwyler 	strcpy(vhost->partition_name, "UNKNOWN");
6872848c7085STyrel Datwyler 	init_waitqueue_head(&vhost->work_wait_q);
6873848c7085STyrel Datwyler 	init_waitqueue_head(&vhost->init_wait_q);
6874848c7085STyrel Datwyler 	INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread);
6875848c7085STyrel Datwyler 	mutex_init(&vhost->passthru_mutex);
6876848c7085STyrel Datwyler 
6877848c7085STyrel Datwyler 	if ((rc = ibmvfc_alloc_mem(vhost)))
6878848c7085STyrel Datwyler 		goto free_scsi_host;
6879848c7085STyrel Datwyler 
6880848c7085STyrel Datwyler 	vhost->work_thread = kthread_run(ibmvfc_work, vhost, "%s_%d", IBMVFC_NAME,
6881848c7085STyrel Datwyler 					 shost->host_no);
6882848c7085STyrel Datwyler 
6883848c7085STyrel Datwyler 	if (IS_ERR(vhost->work_thread)) {
6884848c7085STyrel Datwyler 		dev_err(dev, "Couldn't create kernel thread: %ld\n",
6885848c7085STyrel Datwyler 			PTR_ERR(vhost->work_thread));
6886848c7085STyrel Datwyler 		rc = PTR_ERR(vhost->work_thread);
6887848c7085STyrel Datwyler 		goto free_host_mem;
6888848c7085STyrel Datwyler 	}
6889848c7085STyrel Datwyler 
6890848c7085STyrel Datwyler 	if ((rc = ibmvfc_init_crq(vhost))) {
6891848c7085STyrel Datwyler 		dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc);
6892848c7085STyrel Datwyler 		goto kill_kthread;
6893848c7085STyrel Datwyler 	}
6894848c7085STyrel Datwyler 
6895848c7085STyrel Datwyler 	if ((rc = scsi_add_host(shost, dev)))
6896848c7085STyrel Datwyler 		goto release_crq;
6897848c7085STyrel Datwyler 
6898848c7085STyrel Datwyler 	fc_host_dev_loss_tmo(shost) = IBMVFC_DEV_LOSS_TMO;
6899848c7085STyrel Datwyler 
6900848c7085STyrel Datwyler 	if ((rc = ibmvfc_create_trace_file(&shost->shost_dev.kobj,
6901848c7085STyrel Datwyler 					   &ibmvfc_trace_attr))) {
6902848c7085STyrel Datwyler 		dev_err(dev, "Failed to create trace file. rc=%d\n", rc);
6903848c7085STyrel Datwyler 		goto remove_shost;
6904848c7085STyrel Datwyler 	}
6905848c7085STyrel Datwyler 
6906848c7085STyrel Datwyler 	ibmvfc_init_sub_crqs(vhost);
6907848c7085STyrel Datwyler 
6908848c7085STyrel Datwyler 	dev_set_drvdata(dev, vhost);
6909848c7085STyrel Datwyler 	spin_lock(&ibmvfc_driver_lock);
6910848c7085STyrel Datwyler 	list_add_tail(&vhost->queue, &ibmvfc_head);
6911848c7085STyrel Datwyler 	spin_unlock(&ibmvfc_driver_lock);
6912848c7085STyrel Datwyler 
6913848c7085STyrel Datwyler 	ibmvfc_send_crq_init(vhost);
6914848c7085STyrel Datwyler 	scsi_scan_host(shost);
6915848c7085STyrel Datwyler 	return 0;
6916848c7085STyrel Datwyler 
6917848c7085STyrel Datwyler remove_shost:
6918848c7085STyrel Datwyler 	scsi_remove_host(shost);
6919848c7085STyrel Datwyler release_crq:
6920848c7085STyrel Datwyler 	ibmvfc_release_crq_queue(vhost);
6921848c7085STyrel Datwyler kill_kthread:
6922848c7085STyrel Datwyler 	kthread_stop(vhost->work_thread);
6923848c7085STyrel Datwyler free_host_mem:
6924848c7085STyrel Datwyler 	ibmvfc_free_mem(vhost);
6925848c7085STyrel Datwyler free_scsi_host:
6926848c7085STyrel Datwyler 	scsi_host_put(shost);
6927848c7085STyrel Datwyler out:
6928848c7085STyrel Datwyler 	LEAVE;
6929848c7085STyrel Datwyler 	return rc;
6930848c7085STyrel Datwyler }
6931848c7085STyrel Datwyler 
6932848c7085STyrel Datwyler /**
6933848c7085STyrel Datwyler  * ibmvfc_remove - Adapter hot plug remove entry point
6934848c7085STyrel Datwyler  * @vdev:	vio device struct
6935848c7085STyrel Datwyler  *
6936848c7085STyrel Datwyler  * Return value:
6937848c7085STyrel Datwyler  * 	0
6938848c7085STyrel Datwyler  **/
ibmvfc_remove(struct vio_dev * vdev)6939848c7085STyrel Datwyler static void ibmvfc_remove(struct vio_dev *vdev)
6940848c7085STyrel Datwyler {
6941848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = dev_get_drvdata(&vdev->dev);
6942848c7085STyrel Datwyler 	LIST_HEAD(purge);
6943848c7085STyrel Datwyler 	unsigned long flags;
6944848c7085STyrel Datwyler 
6945848c7085STyrel Datwyler 	ENTER;
6946848c7085STyrel Datwyler 	ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
6947848c7085STyrel Datwyler 
6948848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
6949848c7085STyrel Datwyler 	ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
6950848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
6951848c7085STyrel Datwyler 
6952848c7085STyrel Datwyler 	ibmvfc_wait_while_resetting(vhost);
6953848c7085STyrel Datwyler 	kthread_stop(vhost->work_thread);
6954848c7085STyrel Datwyler 	flush_work(&vhost->rport_add_work_q);
6955848c7085STyrel Datwyler 	fc_remove_host(vhost->host);
6956848c7085STyrel Datwyler 	scsi_remove_host(vhost->host);
6957848c7085STyrel Datwyler 
6958848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
6959848c7085STyrel Datwyler 	ibmvfc_purge_requests(vhost, DID_ERROR);
6960848c7085STyrel Datwyler 	list_splice_init(&vhost->purge, &purge);
6961848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
6962848c7085STyrel Datwyler 	ibmvfc_complete_purge(&purge);
6963848c7085STyrel Datwyler 	ibmvfc_release_sub_crqs(vhost);
6964848c7085STyrel Datwyler 	ibmvfc_release_crq_queue(vhost);
6965848c7085STyrel Datwyler 
6966848c7085STyrel Datwyler 	ibmvfc_free_mem(vhost);
6967848c7085STyrel Datwyler 	spin_lock(&ibmvfc_driver_lock);
6968848c7085STyrel Datwyler 	list_del(&vhost->queue);
6969848c7085STyrel Datwyler 	spin_unlock(&ibmvfc_driver_lock);
6970848c7085STyrel Datwyler 	scsi_host_put(vhost->host);
6971848c7085STyrel Datwyler 	LEAVE;
6972848c7085STyrel Datwyler }
6973848c7085STyrel Datwyler 
6974848c7085STyrel Datwyler /**
6975848c7085STyrel Datwyler  * ibmvfc_resume - Resume from suspend
6976848c7085STyrel Datwyler  * @dev:	device struct
6977848c7085STyrel Datwyler  *
6978848c7085STyrel Datwyler  * We may have lost an interrupt across suspend/resume, so kick the
6979848c7085STyrel Datwyler  * interrupt handler
6980848c7085STyrel Datwyler  *
6981848c7085STyrel Datwyler  */
ibmvfc_resume(struct device * dev)6982848c7085STyrel Datwyler static int ibmvfc_resume(struct device *dev)
6983848c7085STyrel Datwyler {
6984848c7085STyrel Datwyler 	unsigned long flags;
6985848c7085STyrel Datwyler 	struct ibmvfc_host *vhost = dev_get_drvdata(dev);
6986848c7085STyrel Datwyler 	struct vio_dev *vdev = to_vio_dev(dev);
6987848c7085STyrel Datwyler 
6988848c7085STyrel Datwyler 	spin_lock_irqsave(vhost->host->host_lock, flags);
6989848c7085STyrel Datwyler 	vio_disable_interrupts(vdev);
6990848c7085STyrel Datwyler 	tasklet_schedule(&vhost->tasklet);
6991848c7085STyrel Datwyler 	spin_unlock_irqrestore(vhost->host->host_lock, flags);
6992848c7085STyrel Datwyler 	return 0;
6993848c7085STyrel Datwyler }
6994848c7085STyrel Datwyler 
6995848c7085STyrel Datwyler /**
6996848c7085STyrel Datwyler  * ibmvfc_get_desired_dma - Calculate DMA resources needed by the driver
6997848c7085STyrel Datwyler  * @vdev:	vio device struct
6998848c7085STyrel Datwyler  *
6999848c7085STyrel Datwyler  * Return value:
7000848c7085STyrel Datwyler  *	Number of bytes the driver will need to DMA map at the same time in
7001848c7085STyrel Datwyler  *	order to perform well.
7002848c7085STyrel Datwyler  */
ibmvfc_get_desired_dma(struct vio_dev * vdev)7003848c7085STyrel Datwyler static unsigned long ibmvfc_get_desired_dma(struct vio_dev *vdev)
7004848c7085STyrel Datwyler {
7005848c7085STyrel Datwyler 	unsigned long pool_dma;
7006848c7085STyrel Datwyler 
7007848c7085STyrel Datwyler 	pool_dma = (IBMVFC_MAX_SCSI_QUEUES * scsi_qdepth) * sizeof(union ibmvfc_iu);
7008848c7085STyrel Datwyler 	return pool_dma + ((512 * 1024) * driver_template.cmd_per_lun);
7009848c7085STyrel Datwyler }
7010848c7085STyrel Datwyler 
7011848c7085STyrel Datwyler static const struct vio_device_id ibmvfc_device_table[] = {
7012848c7085STyrel Datwyler 	{"fcp", "IBM,vfc-client"},
7013848c7085STyrel Datwyler 	{ "", "" }
7014848c7085STyrel Datwyler };
7015848c7085STyrel Datwyler MODULE_DEVICE_TABLE(vio, ibmvfc_device_table);
7016848c7085STyrel Datwyler 
7017848c7085STyrel Datwyler static const struct dev_pm_ops ibmvfc_pm_ops = {
7018848c7085STyrel Datwyler 	.resume = ibmvfc_resume
7019848c7085STyrel Datwyler };
7020848c7085STyrel Datwyler 
7021848c7085STyrel Datwyler static struct vio_driver ibmvfc_driver = {
7022848c7085STyrel Datwyler 	.id_table = ibmvfc_device_table,
7023848c7085STyrel Datwyler 	.probe = ibmvfc_probe,
7024848c7085STyrel Datwyler 	.remove = ibmvfc_remove,
7025848c7085STyrel Datwyler 	.get_desired_dma = ibmvfc_get_desired_dma,
7026848c7085STyrel Datwyler 	.name = IBMVFC_NAME,
7027848c7085STyrel Datwyler 	.pm = &ibmvfc_pm_ops,
7028848c7085STyrel Datwyler };
7029848c7085STyrel Datwyler 
7030848c7085STyrel Datwyler static struct fc_function_template ibmvfc_transport_functions = {
7031848c7085STyrel Datwyler 	.show_host_fabric_name = 1,
7032848c7085STyrel Datwyler 	.show_host_node_name = 1,
7033848c7085STyrel Datwyler 	.show_host_port_name = 1,
7034848c7085STyrel Datwyler 	.show_host_supported_classes = 1,
7035848c7085STyrel Datwyler 	.show_host_port_type = 1,
7036848c7085STyrel Datwyler 	.show_host_port_id = 1,
7037848c7085STyrel Datwyler 	.show_host_maxframe_size = 1,
7038848c7085STyrel Datwyler 
7039848c7085STyrel Datwyler 	.get_host_port_state = ibmvfc_get_host_port_state,
7040848c7085STyrel Datwyler 	.show_host_port_state = 1,
7041848c7085STyrel Datwyler 
7042848c7085STyrel Datwyler 	.get_host_speed = ibmvfc_get_host_speed,
7043848c7085STyrel Datwyler 	.show_host_speed = 1,
7044848c7085STyrel Datwyler 
7045848c7085STyrel Datwyler 	.issue_fc_host_lip = ibmvfc_issue_fc_host_lip,
7046848c7085STyrel Datwyler 	.terminate_rport_io = ibmvfc_terminate_rport_io,
7047848c7085STyrel Datwyler 
7048848c7085STyrel Datwyler 	.show_rport_maxframe_size = 1,
7049848c7085STyrel Datwyler 	.show_rport_supported_classes = 1,
7050848c7085STyrel Datwyler 
7051848c7085STyrel Datwyler 	.set_rport_dev_loss_tmo = ibmvfc_set_rport_dev_loss_tmo,
7052848c7085STyrel Datwyler 	.show_rport_dev_loss_tmo = 1,
7053848c7085STyrel Datwyler 
7054848c7085STyrel Datwyler 	.get_starget_node_name = ibmvfc_get_starget_node_name,
7055848c7085STyrel Datwyler 	.show_starget_node_name = 1,
7056848c7085STyrel Datwyler 
7057848c7085STyrel Datwyler 	.get_starget_port_name = ibmvfc_get_starget_port_name,
7058848c7085STyrel Datwyler 	.show_starget_port_name = 1,
7059848c7085STyrel Datwyler 
7060848c7085STyrel Datwyler 	.get_starget_port_id = ibmvfc_get_starget_port_id,
7061848c7085STyrel Datwyler 	.show_starget_port_id = 1,
7062848c7085STyrel Datwyler 
7063848c7085STyrel Datwyler 	.max_bsg_segments = 1,
7064848c7085STyrel Datwyler 	.bsg_request = ibmvfc_bsg_request,
7065848c7085STyrel Datwyler 	.bsg_timeout = ibmvfc_bsg_timeout,
7066848c7085STyrel Datwyler };
7067848c7085STyrel Datwyler 
7068848c7085STyrel Datwyler /**
7069848c7085STyrel Datwyler  * ibmvfc_module_init - Initialize the ibmvfc module
7070848c7085STyrel Datwyler  *
7071848c7085STyrel Datwyler  * Return value:
7072848c7085STyrel Datwyler  * 	0 on success / other on failure
7073848c7085STyrel Datwyler  **/
ibmvfc_module_init(void)7074848c7085STyrel Datwyler static int __init ibmvfc_module_init(void)
7075848c7085STyrel Datwyler {
7076848c7085STyrel Datwyler 	int min_max_sectors = PAGE_SIZE >> 9;
7077848c7085STyrel Datwyler 	int rc;
7078848c7085STyrel Datwyler 
7079848c7085STyrel Datwyler 	if (!firmware_has_feature(FW_FEATURE_VIO))
7080848c7085STyrel Datwyler 		return -ENODEV;
7081848c7085STyrel Datwyler 
7082848c7085STyrel Datwyler 	printk(KERN_INFO IBMVFC_NAME": IBM Virtual Fibre Channel Driver version: %s %s\n",
7083848c7085STyrel Datwyler 	       IBMVFC_DRIVER_VERSION, IBMVFC_DRIVER_DATE);
7084848c7085STyrel Datwyler 
7085848c7085STyrel Datwyler 	/*
7086848c7085STyrel Datwyler 	 * Range check the max_sectors module parameter. The upper bounds is
7087848c7085STyrel Datwyler 	 * implicity checked since the parameter is a ushort.
7088848c7085STyrel Datwyler 	 */
7089848c7085STyrel Datwyler 	if (max_sectors < min_max_sectors) {
7090848c7085STyrel Datwyler 		printk(KERN_ERR IBMVFC_NAME ": max_sectors must be at least %d.\n",
7091848c7085STyrel Datwyler 			min_max_sectors);
7092848c7085STyrel Datwyler 		max_sectors = min_max_sectors;
7093848c7085STyrel Datwyler 	}
7094848c7085STyrel Datwyler 
7095848c7085STyrel Datwyler 	ibmvfc_transport_template = fc_attach_transport(&ibmvfc_transport_functions);
7096848c7085STyrel Datwyler 	if (!ibmvfc_transport_template)
7097848c7085STyrel Datwyler 		return -ENOMEM;
7098848c7085STyrel Datwyler 
7099848c7085STyrel Datwyler 	rc = vio_register_driver(&ibmvfc_driver);
7100848c7085STyrel Datwyler 	if (rc)
7101848c7085STyrel Datwyler 		fc_release_transport(ibmvfc_transport_template);
7102848c7085STyrel Datwyler 	return rc;
7103848c7085STyrel Datwyler }
7104848c7085STyrel Datwyler 
7105848c7085STyrel Datwyler /**
7106848c7085STyrel Datwyler  * ibmvfc_module_exit - Teardown the ibmvfc module
7107848c7085STyrel Datwyler  *
7108848c7085STyrel Datwyler  * Return value:
7109848c7085STyrel Datwyler  * 	nothing
7110848c7085STyrel Datwyler  **/
ibmvfc_module_exit(void)7111848c7085STyrel Datwyler static void __exit ibmvfc_module_exit(void)
7112848c7085STyrel Datwyler {
7113848c7085STyrel Datwyler 	vio_unregister_driver(&ibmvfc_driver);
7114848c7085STyrel Datwyler 	fc_release_transport(ibmvfc_transport_template);
7115848c7085STyrel Datwyler }
7116848c7085STyrel Datwyler 
7117848c7085STyrel Datwyler module_init(ibmvfc_module_init);
7118848c7085STyrel Datwyler module_exit(ibmvfc_module_exit);
7119