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 = ∁
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