blob: 91aa4bfcf8d612041ce5ffad18681f02fc01c62f [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Christof Schmitt553448f2008-06-10 18:20:58 +02003 * zfcp device driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Christof Schmitt553448f2008-06-10 18:20:58 +02005 * Implementation of FSF commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
Jens Remus6e2e4902018-05-17 19:15:06 +02007 * Copyright IBM Corp. 2002, 2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
Christof Schmittecf39d42008-12-25 13:39:53 +010010#define KMSG_COMPONENT "zfcp"
11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
Stefan Raspl0997f1c2008-10-16 08:23:39 +020013#include <linux/blktrace_api.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Christof Schmitt9d05ce22009-11-24 16:54:09 +010015#include <scsi/fc/fc_els.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "zfcp_ext.h"
Christof Schmitt4318e082009-11-24 16:54:08 +010017#include "zfcp_fc.h"
Christof Schmittdcd20e22009-08-18 15:43:08 +020018#include "zfcp_dbf.h"
Christof Schmitt34c2b712010-02-17 11:18:59 +010019#include "zfcp_qdio.h"
Christof Schmittb6bd2fb2010-02-17 11:18:50 +010020#include "zfcp_reqlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Christof Schmitt259afe22011-02-22 19:54:44 +010022struct kmem_cache *zfcp_fsf_qtcb_cache;
23
Steffen Maier3638ccd2019-10-01 12:49:49 +020024static bool ber_stop = true;
25module_param(ber_stop, bool, 0600);
26MODULE_PARM_DESC(ber_stop,
27 "Shuts down FCP devices for FCP channels that report a bit-error count in excess of its threshold (default on)");
28
Kees Cook75492a52017-10-16 16:44:34 -070029static void zfcp_fsf_request_timeout_handler(struct timer_list *t)
Christof Schmitt287ac012008-07-02 10:56:40 +020030{
Kees Cook75492a52017-10-16 16:44:34 -070031 struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer);
32 struct zfcp_adapter *adapter = fsf_req->adapter;
Steffen Maier5c13db92017-10-17 18:40:51 +020033
Christof Schmitt339f4f42010-07-16 15:37:43 +020034 zfcp_qdio_siosl(adapter);
Swen Schillig5ffd51a2009-03-02 13:09:04 +010035 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schilligea4a3a62010-12-02 15:16:16 +010036 "fsrth_1");
Christof Schmitt287ac012008-07-02 10:56:40 +020037}
38
39static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
40 unsigned long timeout)
41{
Kees Cook841b86f2017-10-23 09:40:42 +020042 fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
Christof Schmitt287ac012008-07-02 10:56:40 +020043 fsf_req->timer.expires = jiffies + timeout;
44 add_timer(&fsf_req->timer);
45}
46
47static void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req)
48{
49 BUG_ON(!fsf_req->erp_action);
Kees Cook841b86f2017-10-23 09:40:42 +020050 fsf_req->timer.function = zfcp_erp_timeout_handler;
Christof Schmitt287ac012008-07-02 10:56:40 +020051 fsf_req->timer.expires = jiffies + 30 * HZ;
52 add_timer(&fsf_req->timer);
53}
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055/* association between FSF command and FSF QTCB type */
56static u32 fsf_qtcb_type[] = {
57 [FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND,
58 [FSF_QTCB_ABORT_FCP_CMND] = FSF_SUPPORT_COMMAND,
59 [FSF_QTCB_OPEN_PORT_WITH_DID] = FSF_SUPPORT_COMMAND,
60 [FSF_QTCB_OPEN_LUN] = FSF_SUPPORT_COMMAND,
61 [FSF_QTCB_CLOSE_LUN] = FSF_SUPPORT_COMMAND,
62 [FSF_QTCB_CLOSE_PORT] = FSF_SUPPORT_COMMAND,
63 [FSF_QTCB_CLOSE_PHYSICAL_PORT] = FSF_SUPPORT_COMMAND,
64 [FSF_QTCB_SEND_ELS] = FSF_SUPPORT_COMMAND,
65 [FSF_QTCB_SEND_GENERIC] = FSF_SUPPORT_COMMAND,
66 [FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
67 [FSF_QTCB_EXCHANGE_PORT_DATA] = FSF_PORT_COMMAND,
68 [FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
69 [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
70};
71
Christof Schmitt553448f2008-06-10 18:20:58 +020072static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
73{
Christof Schmittff3b24f2008-10-01 12:42:15 +020074 dev_err(&req->adapter->ccw_device->dev, "FCP device not "
75 "operational because of an unsupported FC class\n");
Swen Schilligea4a3a62010-12-02 15:16:16 +010076 zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1");
Christof Schmitt553448f2008-06-10 18:20:58 +020077 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
78}
79
Swen Schilligc41f8cb2008-07-02 10:56:39 +020080/**
81 * zfcp_fsf_req_free - free memory used by fsf request
82 * @fsf_req: pointer to struct zfcp_fsf_req
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +020084void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
Swen Schilligc41f8cb2008-07-02 10:56:39 +020086 if (likely(req->pool)) {
Swen Schilliga4623c42009-08-18 15:43:15 +020087 if (likely(req->qtcb))
88 mempool_free(req->qtcb, req->adapter->pool.qtcb_pool);
Swen Schilligc41f8cb2008-07-02 10:56:39 +020089 mempool_free(req, req->pool);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +020090 return;
91 }
92
Swen Schilliga4623c42009-08-18 15:43:15 +020093 if (likely(req->qtcb))
Christof Schmitt259afe22011-02-22 19:54:44 +010094 kmem_cache_free(zfcp_fsf_qtcb_cache, req->qtcb);
Swen Schilliga4623c42009-08-18 15:43:15 +020095 kfree(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97
Swen Schilligc41f8cb2008-07-02 10:56:39 +020098static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
Swen Schilligecf0c772009-11-24 16:53:58 +0100100 unsigned long flags;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200101 struct fsf_status_read_buffer *sr_buf = req->data;
102 struct zfcp_adapter *adapter = req->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 struct zfcp_port *port;
Christof Schmitt800c0ca2009-11-24 16:54:12 +0100104 int d_id = ntoh24(sr_buf->d_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Swen Schilligecf0c772009-11-24 16:53:58 +0100106 read_lock_irqsave(&adapter->port_list_lock, flags);
107 list_for_each_entry(port, &adapter->port_list, list)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200108 if (port->d_id == d_id) {
Swen Schilligea4a3a62010-12-02 15:16:16 +0100109 zfcp_erp_port_reopen(port, 0, "fssrpc1");
Swen Schilligecf0c772009-11-24 16:53:58 +0100110 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200111 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100112 read_unlock_irqrestore(&adapter->port_list_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113}
114
Swen Schilligedaed852010-09-08 14:40:01 +0200115static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200116 struct fsf_link_down_info *link_down)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200118 struct zfcp_adapter *adapter = req->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200120 if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
121 return;
122
Peter Zijlstra805de8f42015-04-24 01:12:32 +0200123 atomic_or(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
Christof Schmitt70932932009-04-17 15:08:15 +0200124
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100125 zfcp_scsi_schedule_rports_block(adapter);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200126
127 if (!link_down)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 goto out;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200129
130 switch (link_down->error_code) {
131 case FSF_PSQ_LINK_NO_LIGHT:
132 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200133 "There is no light signal from the local "
134 "fibre channel cable\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200135 break;
136 case FSF_PSQ_LINK_WRAP_PLUG:
137 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200138 "There is a wrap plug instead of a fibre "
139 "channel cable\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200140 break;
141 case FSF_PSQ_LINK_NO_FCP:
142 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200143 "The adjacent fibre channel node does not "
144 "support FCP\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200145 break;
146 case FSF_PSQ_LINK_FIRMWARE_UPDATE:
147 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200148 "The FCP device is suspended because of a "
149 "firmware update\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200150 break;
151 case FSF_PSQ_LINK_INVALID_WWPN:
152 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200153 "The FCP device detected a WWPN that is "
154 "duplicate or not valid\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200155 break;
156 case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
157 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200158 "The fibre channel fabric does not support NPIV\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200159 break;
160 case FSF_PSQ_LINK_NO_FCP_RESOURCES:
161 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200162 "The FCP adapter cannot support more NPIV ports\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200163 break;
164 case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
165 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200166 "The adjacent switch cannot support "
167 "more NPIV ports\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200168 break;
169 case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
170 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200171 "The FCP adapter could not log in to the "
172 "fibre channel fabric\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200173 break;
174 case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
175 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200176 "The WWPN assignment file on the FCP adapter "
177 "has been damaged\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200178 break;
179 case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
180 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200181 "The mode table on the FCP adapter "
182 "has been damaged\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200183 break;
184 case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
185 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200186 "All NPIV ports on the FCP adapter have "
187 "been assigned\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200188 break;
189 default:
190 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200191 "The link between the FCP adapter and "
192 "the FC fabric is down\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200193 }
194out:
Swen Schilligedaed852010-09-08 14:40:01 +0200195 zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200196}
197
198static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
199{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200200 struct fsf_status_read_buffer *sr_buf = req->data;
201 struct fsf_link_down_info *ldi =
202 (struct fsf_link_down_info *) &sr_buf->payload;
203
204 switch (sr_buf->status_subtype) {
205 case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200206 case FSF_STATUS_READ_SUB_FDISC_FAILED:
Swen Schilligedaed852010-09-08 14:40:01 +0200207 zfcp_fsf_link_down_info_eval(req, ldi);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200208 break;
209 case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
Swen Schilligedaed852010-09-08 14:40:01 +0200210 zfcp_fsf_link_down_info_eval(req, NULL);
Peter Senna Tschudin3b974872015-08-04 17:11:15 +0200211 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200212}
213
214static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
215{
216 struct zfcp_adapter *adapter = req->adapter;
217 struct fsf_status_read_buffer *sr_buf = req->data;
218
219 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
Swen Schilliga54ca0f2010-12-02 15:16:14 +0100220 zfcp_dbf_hba_fsf_uss("fssrh_1", req);
Christof Schmittc7b279a2011-02-22 19:54:40 +0100221 mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200222 zfcp_fsf_req_free(req);
223 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 }
225
Steffen Maier01009982012-09-04 15:23:30 +0200226 zfcp_dbf_hba_fsf_uss("fssrh_4", req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200227
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200228 switch (sr_buf->status_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 case FSF_STATUS_READ_PORT_CLOSED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200230 zfcp_fsf_status_read_port_closed(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 case FSF_STATUS_READ_INCOMING_ELS:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200233 zfcp_fc_incoming_els(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 case FSF_STATUS_READ_SENSE_DATA_AVAIL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
Swen Schilliga54ca0f2010-12-02 15:16:14 +0100238 zfcp_dbf_hba_bit_err("fssrh_3", req);
Steffen Maier3638ccd2019-10-01 12:49:49 +0200239 if (ber_stop) {
240 dev_warn(&adapter->ccw_device->dev,
241 "All paths over this FCP device are disused because of excessive bit errors\n");
242 zfcp_erp_adapter_shutdown(adapter, 0, "fssrh_b");
243 } else {
244 dev_warn(&adapter->ccw_device->dev,
245 "The error threshold for checksum statistics has been exceeded\n");
246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 case FSF_STATUS_READ_LINK_DOWN:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200249 zfcp_fsf_status_read_link_down(req);
Sven Schuetz2d1e5472010-07-16 15:37:39 +0200250 zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 case FSF_STATUS_READ_LINK_UP:
Christof Schmitt553448f2008-06-10 18:20:58 +0200253 dev_info(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200254 "The local link has been restored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 /* All ports should be marked as ready to run again */
Swen Schilligedaed852010-09-08 14:40:01 +0200256 zfcp_erp_set_adapter_status(adapter,
257 ZFCP_STATUS_COMMON_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 zfcp_erp_adapter_reopen(adapter,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200259 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
260 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schilligea4a3a62010-12-02 15:16:16 +0100261 "fssrh_2");
Sven Schuetz2d1e5472010-07-16 15:37:39 +0200262 zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 break;
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100265 case FSF_STATUS_READ_NOTIFICATION_LOST:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200266 if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
Steffen Maier43f60cb2012-09-04 15:23:35 +0200267 zfcp_fc_conditional_port_scan(adapter);
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100268 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200269 case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200270 adapter->adapter_features = sr_buf->payload.word[0];
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200271 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200273
Christof Schmittc7b279a2011-02-22 19:54:40 +0100274 mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200275 zfcp_fsf_req_free(req);
Swen Schilligd26ab062008-05-19 12:17:37 +0200276
277 atomic_inc(&adapter->stat_miss);
Swen Schillig45446832009-08-18 15:43:17 +0200278 queue_work(adapter->work_queue, &adapter->stat_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200281static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200283 switch (req->qtcb->header.fsf_status_qual.word[0]) {
284 case FSF_SQ_FCP_RSP_AVAILABLE:
285 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
286 case FSF_SQ_NO_RETRY_POSSIBLE:
287 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
288 return;
289 case FSF_SQ_COMMAND_ABORTED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200290 break;
291 case FSF_SQ_NO_RECOM:
292 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200293 "The FCP adapter reported a problem "
294 "that cannot be recovered\n");
Christof Schmitt339f4f42010-07-16 15:37:43 +0200295 zfcp_qdio_siosl(req->adapter);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100296 zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200297 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200299 /* all non-return stats set FSFREQ_ERROR*/
300 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
301}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200303static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
304{
305 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
306 return;
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200307
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200308 switch (req->qtcb->header.fsf_status) {
309 case FSF_UNKNOWN_COMMAND:
310 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200311 "The FCP adapter does not recognize the command 0x%x\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200312 req->qtcb->header.fsf_command);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100313 zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200314 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 case FSF_ADAPTER_STATUS_AVAILABLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200317 zfcp_fsf_fsfstatus_qual_eval(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200322static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200324 struct zfcp_adapter *adapter = req->adapter;
325 struct fsf_qtcb *qtcb = req->qtcb;
326 union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Swen Schillig57717102009-08-18 15:43:21 +0200328 zfcp_dbf_hba_fsf_response(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200330 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
Christof Schmitt4c571c62009-11-24 16:54:15 +0100331 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200332 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 }
334
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200335 switch (qtcb->prefix.prot_status) {
336 case FSF_PROT_GOOD:
337 case FSF_PROT_FSF_STATUS_PRESENTED:
338 return;
339 case FSF_PROT_QTCB_VERSION_ERROR:
340 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200341 "QTCB version 0x%x not supported by FCP adapter "
342 "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
343 psq->word[0], psq->word[1]);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100344 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200346 case FSF_PROT_ERROR_STATE:
347 case FSF_PROT_SEQ_NUMB_ERROR:
Swen Schilligea4a3a62010-12-02 15:16:16 +0100348 zfcp_erp_adapter_reopen(adapter, 0, "fspse_2");
Christof Schmitt4c571c62009-11-24 16:54:15 +0100349 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200351 case FSF_PROT_UNSUPP_QTCB_TYPE:
352 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200353 "The QTCB type is not supported by the FCP adapter\n");
Swen Schilligea4a3a62010-12-02 15:16:16 +0100354 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200356 case FSF_PROT_HOST_CONNECTION_INITIALIZING:
Peter Zijlstra805de8f42015-04-24 01:12:32 +0200357 atomic_or(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200358 &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200360 case FSF_PROT_DUPLICATE_REQUEST_ID:
361 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200362 "0x%Lx is an ambiguous request identifier\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200363 (unsigned long long)qtcb->bottom.support.req_handle);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100364 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200366 case FSF_PROT_LINK_DOWN:
Swen Schilligedaed852010-09-08 14:40:01 +0200367 zfcp_fsf_link_down_info_eval(req, &psq->link_down_info);
Christof Schmitt452b5052010-02-17 11:18:51 +0100368 /* go through reopen to flush pending requests */
Swen Schilligea4a3a62010-12-02 15:16:16 +0100369 zfcp_erp_adapter_reopen(adapter, 0, "fspse_6");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200371 case FSF_PROT_REEST_QUEUE:
372 /* All ports should be marked as ready to run again */
Swen Schilligedaed852010-09-08 14:40:01 +0200373 zfcp_erp_set_adapter_status(adapter,
374 ZFCP_STATUS_COMMON_RUNNING);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200375 zfcp_erp_adapter_reopen(adapter,
376 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100377 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schilligea4a3a62010-12-02 15:16:16 +0100378 "fspse_8");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200379 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 default:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200381 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200382 "0x%x is not a valid transfer protocol status\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200383 qtcb->prefix.prot_status);
Christof Schmitt339f4f42010-07-16 15:37:43 +0200384 zfcp_qdio_siosl(adapter);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100385 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200387 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
390/**
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200391 * zfcp_fsf_req_complete - process completion of a FSF request
392 * @fsf_req: The FSF request that has been completed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 *
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200394 * When a request has been completed either from the FCP adapter,
395 * or it has been dismissed due to a queue shutdown, this function
396 * is called to process the completion status and trigger further
397 * events related to the FSF request.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 */
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200399static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200400{
401 if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
402 zfcp_fsf_status_read_handler(req);
403 return;
404 }
405
406 del_timer(&req->timer);
407 zfcp_fsf_protstatus_eval(req);
408 zfcp_fsf_fsfstatus_eval(req);
409 req->handler(req);
410
411 if (req->erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200412 zfcp_erp_notify(req->erp_action, 0);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200413
414 if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
415 zfcp_fsf_req_free(req);
416 else
Swen Schillig058b8642009-08-18 15:43:14 +0200417 complete(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200418}
419
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200420/**
421 * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
422 * @adapter: pointer to struct zfcp_adapter
423 *
424 * Never ever call this without shutting down the adapter first.
425 * Otherwise the adapter would continue using and corrupting s390 storage.
426 * Included BUG_ON() call to ensure this is done.
427 * ERP is supposed to be the only user of this function.
428 */
429void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
430{
431 struct zfcp_fsf_req *req, *tmp;
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200432 LIST_HEAD(remove_queue);
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200433
434 BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100435 zfcp_reqlist_move(adapter->req_list, &remove_queue);
Swen Schilligbd63eaf2009-08-18 15:43:13 +0200436
437 list_for_each_entry_safe(req, tmp, &remove_queue, list) {
438 list_del(&req->list);
439 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
440 zfcp_fsf_req_complete(req);
441 }
442}
443
Steffen Maierd2201972012-09-04 15:23:29 +0200444#define ZFCP_FSF_PORTSPEED_1GBIT (1 << 0)
445#define ZFCP_FSF_PORTSPEED_2GBIT (1 << 1)
446#define ZFCP_FSF_PORTSPEED_4GBIT (1 << 2)
447#define ZFCP_FSF_PORTSPEED_10GBIT (1 << 3)
448#define ZFCP_FSF_PORTSPEED_8GBIT (1 << 4)
449#define ZFCP_FSF_PORTSPEED_16GBIT (1 << 5)
Jens Remus6e2e4902018-05-17 19:15:06 +0200450#define ZFCP_FSF_PORTSPEED_32GBIT (1 << 6)
451#define ZFCP_FSF_PORTSPEED_64GBIT (1 << 7)
452#define ZFCP_FSF_PORTSPEED_128GBIT (1 << 8)
Steffen Maierd2201972012-09-04 15:23:29 +0200453#define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15)
454
455static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed)
456{
457 u32 fdmi_speed = 0;
458 if (fsf_speed & ZFCP_FSF_PORTSPEED_1GBIT)
459 fdmi_speed |= FC_PORTSPEED_1GBIT;
460 if (fsf_speed & ZFCP_FSF_PORTSPEED_2GBIT)
461 fdmi_speed |= FC_PORTSPEED_2GBIT;
462 if (fsf_speed & ZFCP_FSF_PORTSPEED_4GBIT)
463 fdmi_speed |= FC_PORTSPEED_4GBIT;
464 if (fsf_speed & ZFCP_FSF_PORTSPEED_10GBIT)
465 fdmi_speed |= FC_PORTSPEED_10GBIT;
466 if (fsf_speed & ZFCP_FSF_PORTSPEED_8GBIT)
467 fdmi_speed |= FC_PORTSPEED_8GBIT;
468 if (fsf_speed & ZFCP_FSF_PORTSPEED_16GBIT)
469 fdmi_speed |= FC_PORTSPEED_16GBIT;
Jens Remus6e2e4902018-05-17 19:15:06 +0200470 if (fsf_speed & ZFCP_FSF_PORTSPEED_32GBIT)
471 fdmi_speed |= FC_PORTSPEED_32GBIT;
472 if (fsf_speed & ZFCP_FSF_PORTSPEED_64GBIT)
473 fdmi_speed |= FC_PORTSPEED_64GBIT;
474 if (fsf_speed & ZFCP_FSF_PORTSPEED_128GBIT)
475 fdmi_speed |= FC_PORTSPEED_128GBIT;
Steffen Maierd2201972012-09-04 15:23:29 +0200476 if (fsf_speed & ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED)
477 fdmi_speed |= FC_PORTSPEED_NOT_NEGOTIATED;
478 return fdmi_speed;
479}
480
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200481static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Christof Schmitt9d05ce22009-11-24 16:54:09 +0100483 struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200484 struct zfcp_adapter *adapter = req->adapter;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200485 struct Scsi_Host *shost = adapter->scsi_host;
Christof Schmitt9d05ce22009-11-24 16:54:09 +0100486 struct fc_els_flogi *nsp, *plogi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Christof Schmitt9d05ce22009-11-24 16:54:09 +0100488 /* adjust pointers for missing command code */
489 nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param
490 - sizeof(u32));
491 plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload
492 - sizeof(u32));
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200493
494 if (req->data)
495 memcpy(req->data, bottom, sizeof(*bottom));
496
Steffen Maier9d464fc2017-07-28 12:31:02 +0200497 fc_host_port_name(shost) = be64_to_cpu(nsp->fl_wwpn);
498 fc_host_node_name(shost) = be64_to_cpu(nsp->fl_wwnn);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200499 fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
500
Christof Schmittfaf4cd82010-07-16 15:37:36 +0200501 adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK;
Christof Schmitt8d88cf32010-06-21 10:11:33 +0200502 adapter->stat_read_buf_num = max(bottom->status_read_buf_num,
503 (u16)FSF_STATUS_READS_RECOM);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200504
505 if (fc_host_permanent_port_name(shost) == -1)
506 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
507
Steffen Maier9edf7d72013-04-26 17:34:54 +0200508 zfcp_scsi_set_prot(adapter);
509
510 /* no error return above here, otherwise must fix call chains */
511 /* do not evaluate invalid fields */
512 if (req->qtcb->header.fsf_status == FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE)
513 return 0;
514
515 fc_host_port_id(shost) = ntoh24(bottom->s_id);
516 fc_host_speed(shost) =
517 zfcp_fsf_convert_portspeed(bottom->fc_link_speed);
518
519 adapter->hydra_version = bottom->adapter_type;
520
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200521 switch (bottom->fc_topology) {
522 case FSF_TOPO_P2P:
Christof Schmitt800c0ca2009-11-24 16:54:12 +0100523 adapter->peer_d_id = ntoh24(bottom->peer_d_id);
Steffen Maier9d464fc2017-07-28 12:31:02 +0200524 adapter->peer_wwpn = be64_to_cpu(plogi->fl_wwpn);
525 adapter->peer_wwnn = be64_to_cpu(plogi->fl_wwnn);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200526 fc_host_port_type(shost) = FC_PORTTYPE_PTP;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200527 break;
528 case FSF_TOPO_FABRIC:
Steffen Maierbd77bef2016-08-10 18:30:44 +0200529 if (bottom->connection_features & FSF_FEATURE_NPIV_MODE)
530 fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
531 else
532 fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200533 break;
534 case FSF_TOPO_AL:
535 fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
Christof Schmittdceab652009-05-15 13:18:18 +0200536 /* fall through */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200537 default:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200538 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200539 "Unknown or unsupported arbitrated loop "
540 "fibre channel topology detected\n");
Swen Schilligea4a3a62010-12-02 15:16:16 +0100541 zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200542 return -EIO;
543 }
544
545 return 0;
546}
547
548static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
549{
550 struct zfcp_adapter *adapter = req->adapter;
551 struct fsf_qtcb *qtcb = req->qtcb;
552 struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
553 struct Scsi_Host *shost = adapter->scsi_host;
554
555 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
556 return;
557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 adapter->fsf_lic_version = bottom->lic_version;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200559 adapter->adapter_features = bottom->adapter_features;
560 adapter->connection_features = bottom->connection_features;
6f71d9b2005-04-10 23:04:28 -0500561 adapter->peer_wwpn = 0;
562 adapter->peer_wwnn = 0;
563 adapter->peer_d_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200565 switch (qtcb->header.fsf_status) {
566 case FSF_GOOD:
567 if (zfcp_fsf_exchange_config_evaluate(req))
568 return;
Swen Schillig52ef11a2007-08-28 09:31:09 +0200569
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200570 if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
571 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200572 "FCP adapter maximum QTCB size (%d bytes) "
573 "is too small\n",
574 bottom->max_qtcb_size);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100575 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200576 return;
577 }
Peter Zijlstra805de8f42015-04-24 01:12:32 +0200578 atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200579 &adapter->status);
580 break;
581 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200582 fc_host_node_name(shost) = 0;
583 fc_host_port_name(shost) = 0;
584 fc_host_port_id(shost) = 0;
585 fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
Andreas Herrmannad757cd2006-01-13 02:26:11 +0100586 fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 adapter->hydra_version = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200588
Daniel Hanself76ccaa2013-04-26 17:32:14 +0200589 /* avoids adapter shutdown to be able to recognize
590 * events such as LINK UP */
Peter Zijlstra805de8f42015-04-24 01:12:32 +0200591 atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
Daniel Hanself76ccaa2013-04-26 17:32:14 +0200592 &adapter->status);
Swen Schilligedaed852010-09-08 14:40:01 +0200593 zfcp_fsf_link_down_info_eval(req,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200594 &qtcb->header.fsf_status_qual.link_down_info);
Steffen Maier9edf7d72013-04-26 17:34:54 +0200595 if (zfcp_fsf_exchange_config_evaluate(req))
596 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200597 break;
598 default:
Swen Schilligea4a3a62010-12-02 15:16:16 +0100599 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200600 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
602
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200603 if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 adapter->hardware_version = bottom->hardware_version;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200605 memcpy(fc_host_serial_number(shost), bottom->serial_number,
606 min(FC_SERIAL_NUMBER_SIZE, 17));
607 EBCASC(fc_host_serial_number(shost),
608 min(FC_SERIAL_NUMBER_SIZE, 17));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200611 if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +0200612 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200613 "The FCP adapter only supports newer "
614 "control block versions\n");
Swen Schilligea4a3a62010-12-02 15:16:16 +0100615 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200616 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200618 if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +0200619 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200620 "The FCP adapter only supports older "
621 "control block versions\n");
Swen Schilligea4a3a62010-12-02 15:16:16 +0100622 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624}
625
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200626static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200628 struct zfcp_adapter *adapter = req->adapter;
629 struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port;
630 struct Scsi_Host *shost = adapter->scsi_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200632 if (req->data)
633 memcpy(req->data, bottom, sizeof(*bottom));
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100634
Christof Schmitt02829852009-03-02 13:09:06 +0100635 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100636 fc_host_permanent_port_name(shost) = bottom->wwpn;
Christof Schmitt02829852009-03-02 13:09:06 +0100637 } else
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100638 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
639 fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
Steffen Maierd2201972012-09-04 15:23:29 +0200640 fc_host_supported_speeds(shost) =
641 zfcp_fsf_convert_portspeed(bottom->supported_speed);
Christof Schmitt2d8e62b2010-02-17 11:18:58 +0100642 memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types,
643 FC_FC4_LIST_SIZE);
644 memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types,
645 FC_FC4_LIST_SIZE);
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200648static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200650 struct fsf_qtcb *qtcb = req->qtcb;
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100651
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200652 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 return;
654
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200655 switch (qtcb->header.fsf_status) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200656 case FSF_GOOD:
657 zfcp_fsf_exchange_port_evaluate(req);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200658 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200659 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200660 zfcp_fsf_exchange_port_evaluate(req);
Swen Schilligedaed852010-09-08 14:40:01 +0200661 zfcp_fsf_link_down_info_eval(req,
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200662 &qtcb->header.fsf_status_qual.link_down_info);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200663 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
665}
666
Swen Schilliga4623c42009-08-18 15:43:15 +0200667static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200668{
669 struct zfcp_fsf_req *req;
Swen Schilliga4623c42009-08-18 15:43:15 +0200670
671 if (likely(pool))
672 req = mempool_alloc(pool, GFP_ATOMIC);
673 else
674 req = kmalloc(sizeof(*req), GFP_ATOMIC);
675
676 if (unlikely(!req))
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200677 return NULL;
Swen Schilliga4623c42009-08-18 15:43:15 +0200678
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200679 memset(req, 0, sizeof(*req));
Christof Schmitt88f2a972008-11-04 16:35:07 +0100680 req->pool = pool;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200681 return req;
682}
683
Steffen Maierd39eda52018-05-17 19:14:58 +0200684static struct fsf_qtcb *zfcp_fsf_qtcb_alloc(mempool_t *pool)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200685{
Swen Schilliga4623c42009-08-18 15:43:15 +0200686 struct fsf_qtcb *qtcb;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200687
688 if (likely(pool))
689 qtcb = mempool_alloc(pool, GFP_ATOMIC);
690 else
Christof Schmitt259afe22011-02-22 19:54:44 +0100691 qtcb = kmem_cache_alloc(zfcp_fsf_qtcb_cache, GFP_ATOMIC);
Swen Schilliga4623c42009-08-18 15:43:15 +0200692
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200693 if (unlikely(!qtcb))
694 return NULL;
695
696 memset(qtcb, 0, sizeof(*qtcb));
Swen Schilliga4623c42009-08-18 15:43:15 +0200697 return qtcb;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200698}
699
Swen Schillig564e1c82009-08-18 15:43:19 +0200700static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
Jan Glauber3ec908782011-06-06 14:14:40 +0200701 u32 fsf_cmd, u8 sbtype,
Christof Schmitt1674b402010-04-30 18:09:34 +0200702 mempool_t *pool)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Swen Schillig564e1c82009-08-18 15:43:19 +0200704 struct zfcp_adapter *adapter = qdio->adapter;
Swen Schilliga4623c42009-08-18 15:43:15 +0200705 struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200706
707 if (unlikely(!req))
Christof Schmitt1e9b1642009-07-13 15:06:04 +0200708 return ERR_PTR(-ENOMEM);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200709
710 if (adapter->req_no == 0)
711 adapter->req_no++;
712
713 INIT_LIST_HEAD(&req->list);
Kees Cook75492a52017-10-16 16:44:34 -0700714 timer_setup(&req->timer, NULL, 0);
Swen Schillig058b8642009-08-18 15:43:14 +0200715 init_completion(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200716
717 req->adapter = adapter;
718 req->fsf_command = fsf_cmd;
Christof Schmitt52bfb552009-03-02 13:08:58 +0100719 req->req_id = adapter->req_no;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200720
Swen Schilliga4623c42009-08-18 15:43:15 +0200721 if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
722 if (likely(pool))
Steffen Maierd39eda52018-05-17 19:14:58 +0200723 req->qtcb = zfcp_fsf_qtcb_alloc(
724 adapter->pool.qtcb_pool);
Swen Schilliga4623c42009-08-18 15:43:15 +0200725 else
Steffen Maierd39eda52018-05-17 19:14:58 +0200726 req->qtcb = zfcp_fsf_qtcb_alloc(NULL);
Swen Schilliga4623c42009-08-18 15:43:15 +0200727
728 if (unlikely(!req->qtcb)) {
729 zfcp_fsf_req_free(req);
730 return ERR_PTR(-ENOMEM);
731 }
732
Christof Schmitt5bdecd22010-02-17 11:18:55 +0100733 req->seq_no = adapter->fsf_req_seq_no;
Swen Schillig564e1c82009-08-18 15:43:19 +0200734 req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200735 req->qtcb->prefix.req_id = req->req_id;
736 req->qtcb->prefix.ulp_info = 26;
737 req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
738 req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
739 req->qtcb->header.req_handle = req->req_id;
740 req->qtcb->header.fsf_command = req->fsf_command;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200741 }
742
Christof Schmitt1674b402010-04-30 18:09:34 +0200743 zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype,
744 req->qtcb, sizeof(struct fsf_qtcb));
745
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200746 return req;
747}
748
749static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
750{
751 struct zfcp_adapter *adapter = req->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +0200752 struct zfcp_qdio *qdio = adapter->qdio;
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100753 int with_qtcb = (req->qtcb != NULL);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100754 int req_id = req->req_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200755
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100756 zfcp_reqlist_add(adapter->req_list, req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200757
Swen Schillig706eca42010-07-16 15:37:38 +0200758 req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
Heiko Carstens1aae0562013-01-30 09:49:40 +0100759 req->issued = get_tod_clock();
Christof Schmitt34c2b712010-02-17 11:18:59 +0100760 if (zfcp_qdio_send(qdio, &req->qdio_req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200761 del_timer(&req->timer);
Christof Schmitt37651382008-11-04 16:35:08 +0100762 /* lookup request again, list might have changed */
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100763 zfcp_reqlist_find_rm(adapter->req_list, req_id);
Swen Schilligea4a3a62010-12-02 15:16:16 +0100764 zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200765 return -EIO;
766 }
767
768 /* Don't increase for unsolicited status */
Martin Petermann135ea132009-04-17 15:08:01 +0200769 if (with_qtcb)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200770 adapter->fsf_req_seq_no++;
Christof Schmitt52bfb552009-03-02 13:08:58 +0100771 adapter->req_no++;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200772
773 return 0;
774}
775
776/**
777 * zfcp_fsf_status_read - send status read request
778 * @adapter: pointer to struct zfcp_adapter
779 * @req_flags: request flags
780 * Returns: 0 on success, ERROR otherwise
781 */
Swen Schillig564e1c82009-08-18 15:43:19 +0200782int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200783{
Swen Schillig564e1c82009-08-18 15:43:19 +0200784 struct zfcp_adapter *adapter = qdio->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200785 struct zfcp_fsf_req *req;
786 struct fsf_status_read_buffer *sr_buf;
Christof Schmittc7b279a2011-02-22 19:54:40 +0100787 struct page *page;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200788 int retval = -EIO;
789
Christof Schmitt44a24cb2010-09-08 14:39:57 +0200790 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +0200791 if (zfcp_qdio_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Martin Peschke75a14082013-08-22 17:49:31 +0200794 req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
795 SBAL_SFLAGS0_TYPE_STATUS,
Swen Schilliga4623c42009-08-18 15:43:15 +0200796 adapter->pool.status_read_req);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +0200797 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200798 retval = PTR_ERR(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 goto out;
800 }
801
Christof Schmittc7b279a2011-02-22 19:54:40 +0100802 page = mempool_alloc(adapter->pool.sr_data, GFP_ATOMIC);
803 if (!page) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200804 retval = -ENOMEM;
805 goto failed_buf;
806 }
Christof Schmittc7b279a2011-02-22 19:54:40 +0100807 sr_buf = page_address(page);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200808 memset(sr_buf, 0, sizeof(*sr_buf));
809 req->data = sr_buf;
Christof Schmitt1674b402010-04-30 18:09:34 +0200810
811 zfcp_qdio_fill_next(qdio, &req->qdio_req, sr_buf, sizeof(*sr_buf));
812 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200813
814 retval = zfcp_fsf_req_send(req);
815 if (retval)
816 goto failed_req_send;
817
818 goto out;
819
820failed_req_send:
Swen Schilliga54ca0f2010-12-02 15:16:14 +0100821 req->data = NULL;
Christof Schmittc7b279a2011-02-22 19:54:40 +0100822 mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200823failed_buf:
Swen Schilliga54ca0f2010-12-02 15:16:14 +0100824 zfcp_dbf_hba_fsf_uss("fssr__1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200825 zfcp_fsf_req_free(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200826out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +0200827 spin_unlock_irq(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 return retval;
829}
830
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200831static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200833 struct scsi_device *sdev = req->data;
Martin Peschked436de82012-09-04 15:23:36 +0200834 struct zfcp_scsi_dev *zfcp_sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200835 union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200837 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
838 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Martin Peschked436de82012-09-04 15:23:36 +0200840 zfcp_sdev = sdev_to_zfcp(sdev);
841
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200842 switch (req->qtcb->header.fsf_status) {
843 case FSF_PORT_HANDLE_NOT_VALID:
844 if (fsq->word[0] == fsq->word[1]) {
Christof Schmittb62a8d92010-09-08 14:39:55 +0200845 zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0,
Swen Schilligea4a3a62010-12-02 15:16:16 +0100846 "fsafch1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200847 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200850 case FSF_LUN_HANDLE_NOT_VALID:
851 if (fsq->word[0] == fsq->word[1]) {
Swen Schilligea4a3a62010-12-02 15:16:16 +0100852 zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200853 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200856 case FSF_FCP_COMMAND_DOES_NOT_EXIST:
857 req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200859 case FSF_PORT_BOXED:
Swen Schilligedaed852010-09-08 14:40:01 +0200860 zfcp_erp_set_port_status(zfcp_sdev->port,
861 ZFCP_STATUS_COMMON_ACCESS_BOXED);
862 zfcp_erp_port_reopen(zfcp_sdev->port,
Swen Schilligea4a3a62010-12-02 15:16:16 +0100863 ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3");
Christof Schmitt4c571c62009-11-24 16:54:15 +0100864 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200865 break;
866 case FSF_LUN_BOXED:
Swen Schilligedaed852010-09-08 14:40:01 +0200867 zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
868 zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schilligea4a3a62010-12-02 15:16:16 +0100869 "fsafch4");
Christof Schmitt4c571c62009-11-24 16:54:15 +0100870 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200871 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 case FSF_ADAPTER_STATUS_AVAILABLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200873 switch (fsq->word[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200875 zfcp_fc_test_link(zfcp_sdev->port);
Christof Schmittdceab652009-05-15 13:18:18 +0200876 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200878 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 break;
880 }
881 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 case FSF_GOOD:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200883 req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
884 break;
885 }
886}
887
888/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200889 * zfcp_fsf_abort_fcp_cmnd - abort running SCSI command
890 * @scmnd: The SCSI command to abort
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200891 * Returns: pointer to struct zfcp_fsf_req
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200892 */
893
Christof Schmittb62a8d92010-09-08 14:39:55 +0200894struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200895{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200896 struct zfcp_fsf_req *req = NULL;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200897 struct scsi_device *sdev = scmnd->device;
898 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
899 struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio;
900 unsigned long old_req_id = (unsigned long) scmnd->host_scribble;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200901
Christof Schmitt44a24cb2010-09-08 14:39:57 +0200902 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +0200903 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200904 goto out;
Swen Schillig564e1c82009-08-18 15:43:19 +0200905 req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND,
Jan Glauber3ec908782011-06-06 14:14:40 +0200906 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +0200907 qdio->adapter->pool.scsi_abort);
Swen Schillig633528c2008-11-26 18:07:37 +0100908 if (IS_ERR(req)) {
909 req = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200910 goto out;
Swen Schillig633528c2008-11-26 18:07:37 +0100911 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200912
Christof Schmittb62a8d92010-09-08 14:39:55 +0200913 if (unlikely(!(atomic_read(&zfcp_sdev->status) &
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200914 ZFCP_STATUS_COMMON_UNBLOCKED)))
915 goto out_error_free;
916
Christof Schmitt1674b402010-04-30 18:09:34 +0200917 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200918
Swen Schillig6fbf25e2010-11-17 14:23:41 +0100919 req->data = sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200920 req->handler = zfcp_fsf_abort_fcp_command_handler;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200921 req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
922 req->qtcb->header.port_handle = zfcp_sdev->port->handle;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200923 req->qtcb->bottom.support.req_handle = (u64) old_req_id;
924
925 zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
926 if (!zfcp_fsf_req_send(req))
927 goto out;
928
929out_error_free:
930 zfcp_fsf_req_free(req);
931 req = NULL;
932out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +0200933 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200934 return req;
935}
936
937static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
938{
939 struct zfcp_adapter *adapter = req->adapter;
Christof Schmitt7c7dc192009-11-24 16:54:13 +0100940 struct zfcp_fsf_ct_els *ct = req->data;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200941 struct fsf_qtcb_header *header = &req->qtcb->header;
942
Christof Schmitt7c7dc192009-11-24 16:54:13 +0100943 ct->status = -EINVAL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200944
945 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
946 goto skip_fsfstatus;
947
948 switch (header->fsf_status) {
949 case FSF_GOOD:
Christof Schmitt7c7dc192009-11-24 16:54:13 +0100950 ct->status = 0;
Steffen Maier975171b2017-07-28 12:30:53 +0200951 zfcp_dbf_san_res("fsscth2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200952 break;
953 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
954 zfcp_fsf_class_not_supp(req);
955 break;
956 case FSF_ADAPTER_STATUS_AVAILABLE:
957 switch (header->fsf_status_qual.word[0]){
958 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200959 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
960 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
961 break;
962 }
963 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200964 case FSF_PORT_BOXED:
Christof Schmitt4c571c62009-11-24 16:54:15 +0100965 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200966 break;
967 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +0100968 zfcp_erp_adapter_reopen(adapter, 0, "fsscth1");
Christof Schmittdceab652009-05-15 13:18:18 +0200969 /* fall through */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200970 case FSF_GENERIC_COMMAND_REJECTED:
971 case FSF_PAYLOAD_SIZE_MISMATCH:
972 case FSF_REQUEST_SIZE_TOO_LARGE:
973 case FSF_RESPONSE_SIZE_TOO_LARGE:
974 case FSF_SBAL_MISMATCH:
975 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
976 break;
977 }
978
979skip_fsfstatus:
Christof Schmitt7c7dc192009-11-24 16:54:13 +0100980 if (ct->handler)
981 ct->handler(ct->handler_data);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200982}
983
Christof Schmitt1674b402010-04-30 18:09:34 +0200984static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
985 struct zfcp_qdio_req *q_req,
Christof Schmitt426f6052009-07-13 15:06:06 +0200986 struct scatterlist *sg_req,
987 struct scatterlist *sg_resp)
988{
Christof Schmitt1674b402010-04-30 18:09:34 +0200989 zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_req), sg_req->length);
990 zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_resp), sg_resp->length);
991 zfcp_qdio_set_sbale_last(qdio, q_req);
Christof Schmitt426f6052009-07-13 15:06:06 +0200992}
993
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +0100994static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
995 struct scatterlist *sg_req,
Swen Schillig01b04752010-07-16 15:37:37 +0200996 struct scatterlist *sg_resp)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200997{
Swen Schillig42428f72009-08-18 15:43:18 +0200998 struct zfcp_adapter *adapter = req->adapter;
Swen Schillig86a96682011-08-15 14:40:32 +0200999 struct zfcp_qdio *qdio = adapter->qdio;
1000 struct fsf_qtcb *qtcb = req->qtcb;
Swen Schillig42428f72009-08-18 15:43:18 +02001001 u32 feat = adapter->adapter_features;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001002
Swen Schillig86a96682011-08-15 14:40:32 +02001003 if (zfcp_adapter_multi_buffer_active(adapter)) {
1004 if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
1005 return -EIO;
Steffen Maier70369f82016-08-10 18:30:45 +02001006 qtcb->bottom.support.req_buf_length =
1007 zfcp_qdio_real_bytes(sg_req);
Swen Schillig86a96682011-08-15 14:40:32 +02001008 if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
1009 return -EIO;
Steffen Maier70369f82016-08-10 18:30:45 +02001010 qtcb->bottom.support.resp_buf_length =
1011 zfcp_qdio_real_bytes(sg_resp);
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001012
LABBE Corentin7d918692017-07-28 12:30:47 +02001013 zfcp_qdio_set_data_div(qdio, &req->qdio_req, sg_nents(sg_req));
Swen Schillig86a96682011-08-15 14:40:32 +02001014 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
1015 zfcp_qdio_set_scount(qdio, &req->qdio_req);
Christof Schmitt426f6052009-07-13 15:06:06 +02001016 return 0;
1017 }
1018
1019 /* use single, unchained SBAL if it can hold the request */
Swen Schillig30b67772010-06-21 10:11:31 +02001020 if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) {
Swen Schillig86a96682011-08-15 14:40:32 +02001021 zfcp_fsf_setup_ct_els_unchained(qdio, &req->qdio_req,
Christof Schmitt1674b402010-04-30 18:09:34 +02001022 sg_req, sg_resp);
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001023 return 0;
1024 }
1025
Swen Schillig86a96682011-08-15 14:40:32 +02001026 if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS))
1027 return -EOPNOTSUPP;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001028
Swen Schillig86a96682011-08-15 14:40:32 +02001029 if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
Christof Schmitt9072df42009-07-13 15:06:07 +02001030 return -EIO;
Swen Schillig86a96682011-08-15 14:40:32 +02001031
1032 qtcb->bottom.support.req_buf_length = zfcp_qdio_real_bytes(sg_req);
1033
1034 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
1035 zfcp_qdio_skip_to_last_sbale(qdio, &req->qdio_req);
1036
1037 if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
1038 return -EIO;
1039
1040 qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp);
1041
1042 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001043
Christof Schmittb1a58982009-09-24 10:23:21 +02001044 return 0;
1045}
1046
1047static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
1048 struct scatterlist *sg_req,
1049 struct scatterlist *sg_resp,
Swen Schillig01b04752010-07-16 15:37:37 +02001050 unsigned int timeout)
Christof Schmittb1a58982009-09-24 10:23:21 +02001051{
1052 int ret;
1053
Swen Schillig01b04752010-07-16 15:37:37 +02001054 ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp);
Christof Schmittb1a58982009-09-24 10:23:21 +02001055 if (ret)
1056 return ret;
1057
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001058 /* common settings for ct/gs and els requests */
Swen Schillig51375ee2010-01-14 17:19:02 +01001059 if (timeout > 255)
1060 timeout = 255; /* max value accepted by hardware */
Christof Schmitt98fc4d52009-08-18 15:43:26 +02001061 req->qtcb->bottom.support.service_class = FSF_CLASS_3;
Swen Schillig51375ee2010-01-14 17:19:02 +01001062 req->qtcb->bottom.support.timeout = timeout;
1063 zfcp_fsf_start_timer(req, (timeout + 10) * HZ);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001064
1065 return 0;
1066}
1067
1068/**
1069 * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1070 * @ct: pointer to struct zfcp_send_ct with data for request
1071 * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001072 */
Christof Schmitt7c7dc192009-11-24 16:54:13 +01001073int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
Swen Schillig51375ee2010-01-14 17:19:02 +01001074 struct zfcp_fsf_ct_els *ct, mempool_t *pool,
1075 unsigned int timeout)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001076{
Swen Schillig564e1c82009-08-18 15:43:19 +02001077 struct zfcp_qdio *qdio = wka_port->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001078 struct zfcp_fsf_req *req;
1079 int ret = -EIO;
1080
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001081 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001082 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001083 goto out;
1084
Christof Schmitt1674b402010-04-30 18:09:34 +02001085 req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC,
Jan Glauber3ec908782011-06-06 14:14:40 +02001086 SBAL_SFLAGS0_TYPE_WRITE_READ, pool);
Swen Schillig09a46c62009-08-18 15:43:16 +02001087
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001088 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001089 ret = PTR_ERR(req);
1090 goto out;
1091 }
1092
Swen Schillig09a46c62009-08-18 15:43:16 +02001093 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig01b04752010-07-16 15:37:37 +02001094 ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001095 if (ret)
1096 goto failed_send;
1097
1098 req->handler = zfcp_fsf_send_ct_handler;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001099 req->qtcb->header.port_handle = wka_port->handle;
Steffen Maier771bf032016-08-10 18:30:51 +02001100 ct->d_id = wka_port->d_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001101 req->data = ct;
1102
Swen Schillig2c55b752010-12-02 15:16:13 +01001103 zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001104
1105 ret = zfcp_fsf_req_send(req);
1106 if (ret)
1107 goto failed_send;
1108
1109 goto out;
1110
1111failed_send:
1112 zfcp_fsf_req_free(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001113out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001114 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001115 return ret;
1116}
1117
1118static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
1119{
Christof Schmitt7c7dc192009-11-24 16:54:13 +01001120 struct zfcp_fsf_ct_els *send_els = req->data;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001121 struct fsf_qtcb_header *header = &req->qtcb->header;
1122
1123 send_els->status = -EINVAL;
1124
1125 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
1126 goto skip_fsfstatus;
1127
1128 switch (header->fsf_status) {
1129 case FSF_GOOD:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001130 send_els->status = 0;
Steffen Maier975171b2017-07-28 12:30:53 +02001131 zfcp_dbf_san_res("fsselh1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001132 break;
1133 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
1134 zfcp_fsf_class_not_supp(req);
1135 break;
1136 case FSF_ADAPTER_STATUS_AVAILABLE:
1137 switch (header->fsf_status_qual.word[0]){
1138 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001139 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1140 case FSF_SQ_RETRY_IF_POSSIBLE:
1141 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1142 break;
1143 }
1144 break;
1145 case FSF_ELS_COMMAND_REJECTED:
1146 case FSF_PAYLOAD_SIZE_MISMATCH:
1147 case FSF_REQUEST_SIZE_TOO_LARGE:
1148 case FSF_RESPONSE_SIZE_TOO_LARGE:
1149 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001150 case FSF_SBAL_MISMATCH:
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001151 /* should never occur, avoided in zfcp_fsf_send_els */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001152 /* fall through */
1153 default:
1154 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1155 break;
1156 }
1157skip_fsfstatus:
1158 if (send_els->handler)
1159 send_els->handler(send_els->handler_data);
1160}
1161
1162/**
1163 * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1164 * @els: pointer to struct zfcp_send_els with data for the command
1165 */
Christof Schmitt7c7dc192009-11-24 16:54:13 +01001166int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
Swen Schillig51375ee2010-01-14 17:19:02 +01001167 struct zfcp_fsf_ct_els *els, unsigned int timeout)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001168{
1169 struct zfcp_fsf_req *req;
Christof Schmitt7c7dc192009-11-24 16:54:13 +01001170 struct zfcp_qdio *qdio = adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001171 int ret = -EIO;
1172
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001173 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001174 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001175 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001176
Christof Schmitt1674b402010-04-30 18:09:34 +02001177 req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS,
Jan Glauber3ec908782011-06-06 14:14:40 +02001178 SBAL_SFLAGS0_TYPE_WRITE_READ, NULL);
Swen Schillig09a46c62009-08-18 15:43:16 +02001179
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001180 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001181 ret = PTR_ERR(req);
1182 goto out;
1183 }
1184
Swen Schillig09a46c62009-08-18 15:43:16 +02001185 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schillig01b04752010-07-16 15:37:37 +02001186
Swen Schillig86a96682011-08-15 14:40:32 +02001187 if (!zfcp_adapter_multi_buffer_active(adapter))
1188 zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
Swen Schillig01b04752010-07-16 15:37:37 +02001189
1190 ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
Swen Schillig44cc76f2008-10-01 12:42:16 +02001191
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001192 if (ret)
1193 goto failed_send;
1194
Christof Schmitt7c7dc192009-11-24 16:54:13 +01001195 hton24(req->qtcb->bottom.support.d_id, d_id);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001196 req->handler = zfcp_fsf_send_els_handler;
Steffen Maier771bf032016-08-10 18:30:51 +02001197 els->d_id = d_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001198 req->data = els;
1199
Swen Schillig2c55b752010-12-02 15:16:13 +01001200 zfcp_dbf_san_req("fssels1", req, d_id);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001201
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001202 ret = zfcp_fsf_req_send(req);
1203 if (ret)
1204 goto failed_send;
1205
1206 goto out;
1207
1208failed_send:
1209 zfcp_fsf_req_free(req);
1210out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001211 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001212 return ret;
1213}
1214
1215int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
1216{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001217 struct zfcp_fsf_req *req;
Swen Schillig564e1c82009-08-18 15:43:19 +02001218 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001219 int retval = -EIO;
1220
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001221 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001222 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001223 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001224
Swen Schillig564e1c82009-08-18 15:43:19 +02001225 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
Jan Glauber3ec908782011-06-06 14:14:40 +02001226 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001227 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001228
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001229 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001230 retval = PTR_ERR(req);
1231 goto out;
1232 }
1233
Swen Schillig09a46c62009-08-18 15:43:16 +02001234 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001235 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001236
1237 req->qtcb->bottom.config.feature_selection =
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001238 FSF_FEATURE_NOTIFICATION_LOST |
1239 FSF_FEATURE_UPDATE_ALERT;
1240 req->erp_action = erp_action;
1241 req->handler = zfcp_fsf_exchange_config_data_handler;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001242 erp_action->fsf_req_id = req->req_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001243
Christof Schmitt287ac012008-07-02 10:56:40 +02001244 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001245 retval = zfcp_fsf_req_send(req);
1246 if (retval) {
1247 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001248 erp_action->fsf_req_id = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001249 }
1250out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001251 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001252 return retval;
1253}
1254
Swen Schillig564e1c82009-08-18 15:43:19 +02001255int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001256 struct fsf_qtcb_bottom_config *data)
1257{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001258 struct zfcp_fsf_req *req = NULL;
1259 int retval = -EIO;
1260
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001261 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001262 if (zfcp_qdio_sbal_get(qdio))
Christof Schmittada81b72009-04-17 15:08:03 +02001263 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001264
Christof Schmitt1674b402010-04-30 18:09:34 +02001265 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
Jan Glauber3ec908782011-06-06 14:14:40 +02001266 SBAL_SFLAGS0_TYPE_READ, NULL);
Swen Schillig09a46c62009-08-18 15:43:16 +02001267
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001268 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001269 retval = PTR_ERR(req);
Christof Schmittada81b72009-04-17 15:08:03 +02001270 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001271 }
1272
Christof Schmitt1674b402010-04-30 18:09:34 +02001273 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001274 req->handler = zfcp_fsf_exchange_config_data_handler;
1275
1276 req->qtcb->bottom.config.feature_selection =
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001277 FSF_FEATURE_NOTIFICATION_LOST |
1278 FSF_FEATURE_UPDATE_ALERT;
1279
1280 if (data)
1281 req->data = data;
1282
1283 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1284 retval = zfcp_fsf_req_send(req);
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001285 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001286 if (!retval)
Swen Schillig058b8642009-08-18 15:43:14 +02001287 wait_for_completion(&req->completion);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001288
1289 zfcp_fsf_req_free(req);
Christof Schmittada81b72009-04-17 15:08:03 +02001290 return retval;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001291
Christof Schmittada81b72009-04-17 15:08:03 +02001292out_unlock:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001293 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001294 return retval;
1295}
1296
1297/**
1298 * zfcp_fsf_exchange_port_data - request information about local port
1299 * @erp_action: ERP action for the adapter for which port data is requested
1300 * Returns: 0 on success, error otherwise
1301 */
1302int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
1303{
Swen Schillig564e1c82009-08-18 15:43:19 +02001304 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001305 struct zfcp_fsf_req *req;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001306 int retval = -EIO;
1307
Swen Schillig564e1c82009-08-18 15:43:19 +02001308 if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001309 return -EOPNOTSUPP;
1310
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001311 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001312 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001313 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001314
Swen Schillig564e1c82009-08-18 15:43:19 +02001315 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
Jan Glauber3ec908782011-06-06 14:14:40 +02001316 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001317 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001318
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001319 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001320 retval = PTR_ERR(req);
1321 goto out;
1322 }
1323
Swen Schillig09a46c62009-08-18 15:43:16 +02001324 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001325 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001326
1327 req->handler = zfcp_fsf_exchange_port_data_handler;
1328 req->erp_action = erp_action;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001329 erp_action->fsf_req_id = req->req_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001330
Christof Schmitt287ac012008-07-02 10:56:40 +02001331 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001332 retval = zfcp_fsf_req_send(req);
1333 if (retval) {
1334 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001335 erp_action->fsf_req_id = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001336 }
1337out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001338 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001339 return retval;
1340}
1341
1342/**
1343 * zfcp_fsf_exchange_port_data_sync - request information about local port
Swen Schillig564e1c82009-08-18 15:43:19 +02001344 * @qdio: pointer to struct zfcp_qdio
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001345 * @data: pointer to struct fsf_qtcb_bottom_port
1346 * Returns: 0 on success, error otherwise
1347 */
Swen Schillig564e1c82009-08-18 15:43:19 +02001348int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001349 struct fsf_qtcb_bottom_port *data)
1350{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001351 struct zfcp_fsf_req *req = NULL;
1352 int retval = -EIO;
1353
Swen Schillig564e1c82009-08-18 15:43:19 +02001354 if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001355 return -EOPNOTSUPP;
1356
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001357 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001358 if (zfcp_qdio_sbal_get(qdio))
Christof Schmittada81b72009-04-17 15:08:03 +02001359 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001360
Christof Schmitt1674b402010-04-30 18:09:34 +02001361 req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
Jan Glauber3ec908782011-06-06 14:14:40 +02001362 SBAL_SFLAGS0_TYPE_READ, NULL);
Swen Schillig09a46c62009-08-18 15:43:16 +02001363
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001364 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001365 retval = PTR_ERR(req);
Christof Schmittada81b72009-04-17 15:08:03 +02001366 goto out_unlock;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001367 }
1368
1369 if (data)
1370 req->data = data;
1371
Christof Schmitt1674b402010-04-30 18:09:34 +02001372 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001373
1374 req->handler = zfcp_fsf_exchange_port_data_handler;
1375 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1376 retval = zfcp_fsf_req_send(req);
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001377 spin_unlock_irq(&qdio->req_q_lock);
Christof Schmittada81b72009-04-17 15:08:03 +02001378
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001379 if (!retval)
Swen Schillig058b8642009-08-18 15:43:14 +02001380 wait_for_completion(&req->completion);
1381
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001382 zfcp_fsf_req_free(req);
1383
1384 return retval;
Christof Schmittada81b72009-04-17 15:08:03 +02001385
1386out_unlock:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001387 spin_unlock_irq(&qdio->req_q_lock);
Christof Schmittada81b72009-04-17 15:08:03 +02001388 return retval;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001389}
1390
1391static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
1392{
1393 struct zfcp_port *port = req->data;
1394 struct fsf_qtcb_header *header = &req->qtcb->header;
Christof Schmitt9d05ce22009-11-24 16:54:09 +01001395 struct fc_els_flogi *plogi;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001396
1397 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Martin Petermanna17c5852009-05-15 13:18:19 +02001398 goto out;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001399
1400 switch (header->fsf_status) {
1401 case FSF_PORT_ALREADY_OPEN:
1402 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001403 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1404 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001405 "Not enough FCP adapter resources to open "
Swen Schillig7ba58c92008-10-01 12:42:18 +02001406 "remote port 0x%016Lx\n",
1407 (unsigned long long)port->wwpn);
Swen Schilligedaed852010-09-08 14:40:01 +02001408 zfcp_erp_set_port_status(port,
1409 ZFCP_STATUS_COMMON_ERP_FAILED);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001410 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1411 break;
1412 case FSF_ADAPTER_STATUS_AVAILABLE:
1413 switch (header->fsf_status_qual.word[0]) {
1414 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Steffen Maier394134f2017-07-28 12:31:00 +02001415 /* no zfcp_fc_test_link() with failed open port */
1416 /* fall through */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001417 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001418 case FSF_SQ_NO_RETRY_POSSIBLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001419 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1420 break;
1421 }
1422 break;
1423 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 port->handle = header->port_handle;
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001425 atomic_or(ZFCP_STATUS_COMMON_OPEN |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001427 atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_BOXED,
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001428 &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 /* check whether D_ID has changed during open */
1430 /*
1431 * FIXME: This check is not airtight, as the FCP channel does
1432 * not monitor closures of target port connections caused on
1433 * the remote side. Thus, they might miss out on invalidating
1434 * locally cached WWPNs (and other N_Port parameters) of gone
1435 * target ports. So, our heroic attempt to make things safe
1436 * could be undermined by 'open port' response data tagged with
1437 * obsolete WWPNs. Another reason to monitor potential
1438 * connection closures ourself at least (by interpreting
1439 * incoming ELS' and unsolicited status). It just crosses my
1440 * mind that one should be able to cross-check by means of
1441 * another GID_PN straight after a port has been opened.
1442 * Alternately, an ADISC/PDISC ELS should suffice, as well.
1443 */
Christof Schmitt9d05ce22009-11-24 16:54:09 +01001444 plogi = (struct fc_els_flogi *) req->qtcb->bottom.support.els;
Christof Schmitt39eb7e9a2008-12-19 16:57:01 +01001445 if (req->qtcb->bottom.support.els1_length >=
Christof Schmitt9d05ce22009-11-24 16:54:09 +01001446 FSF_PLOGI_MIN_LEN)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001447 zfcp_fc_plogi_evaluate(port, plogi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 case FSF_UNKNOWN_OP_SUBTYPE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001450 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 break;
1452 }
Martin Petermanna17c5852009-05-15 13:18:19 +02001453
1454out:
Christof Schmitt615f59e2010-02-17 11:18:56 +01001455 put_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456}
1457
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001458/**
1459 * zfcp_fsf_open_port - create and send open port request
1460 * @erp_action: pointer to struct zfcp_erp_action
1461 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001463int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464{
Swen Schillig564e1c82009-08-18 15:43:19 +02001465 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Martin Petermanna17c5852009-05-15 13:18:19 +02001466 struct zfcp_port *port = erp_action->port;
Swen Schillig564e1c82009-08-18 15:43:19 +02001467 struct zfcp_fsf_req *req;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001468 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001470 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001471 if (zfcp_qdio_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
Swen Schillig564e1c82009-08-18 15:43:19 +02001474 req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
Jan Glauber3ec908782011-06-06 14:14:40 +02001475 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001476 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001477
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001478 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001479 retval = PTR_ERR(req);
1480 goto out;
1481 }
1482
Swen Schillig09a46c62009-08-18 15:43:16 +02001483 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001484 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001486 req->handler = zfcp_fsf_open_port_handler;
Christof Schmitt800c0ca2009-11-24 16:54:12 +01001487 hton24(req->qtcb->bottom.support.d_id, port->d_id);
Martin Petermanna17c5852009-05-15 13:18:19 +02001488 req->data = port;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001489 req->erp_action = erp_action;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001490 erp_action->fsf_req_id = req->req_id;
Christof Schmitt615f59e2010-02-17 11:18:56 +01001491 get_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
Christof Schmitt287ac012008-07-02 10:56:40 +02001493 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001494 retval = zfcp_fsf_req_send(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if (retval) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001496 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001497 erp_action->fsf_req_id = 0;
Christof Schmitt615f59e2010-02-17 11:18:56 +01001498 put_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001500out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001501 spin_unlock_irq(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 return retval;
1503}
1504
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001505static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001507 struct zfcp_port *port = req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001509 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001510 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001512 switch (req->qtcb->header.fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +01001514 zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001515 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 case FSF_GOOD:
Swen Schilligedaed852010-09-08 14:40:01 +02001520 zfcp_erp_clear_port_status(port, ZFCP_STATUS_COMMON_OPEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523}
1524
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001525/**
1526 * zfcp_fsf_close_port - create and send close port request
1527 * @erp_action: pointer to struct zfcp_erp_action
1528 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001530int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
Swen Schillig564e1c82009-08-18 15:43:19 +02001532 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001533 struct zfcp_fsf_req *req;
1534 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001536 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001537 if (zfcp_qdio_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Swen Schillig564e1c82009-08-18 15:43:19 +02001540 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
Jan Glauber3ec908782011-06-06 14:14:40 +02001541 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001542 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001543
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001544 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001545 retval = PTR_ERR(req);
1546 goto out;
1547 }
1548
Swen Schillig09a46c62009-08-18 15:43:16 +02001549 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001550 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001552 req->handler = zfcp_fsf_close_port_handler;
1553 req->data = erp_action->port;
1554 req->erp_action = erp_action;
1555 req->qtcb->header.port_handle = erp_action->port->handle;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001556 erp_action->fsf_req_id = req->req_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
Christof Schmitt287ac012008-07-02 10:56:40 +02001558 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001559 retval = zfcp_fsf_req_send(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 if (retval) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001561 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001562 erp_action->fsf_req_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001564out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001565 spin_unlock_irq(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 return retval;
1567}
1568
Swen Schillig5ab944f2008-10-01 12:42:17 +02001569static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
1570{
Christof Schmittbd0072e2009-11-24 16:54:11 +01001571 struct zfcp_fc_wka_port *wka_port = req->data;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001572 struct fsf_qtcb_header *header = &req->qtcb->header;
1573
1574 if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
Christof Schmittbd0072e2009-11-24 16:54:11 +01001575 wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001576 goto out;
1577 }
1578
1579 switch (header->fsf_status) {
1580 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1581 dev_warn(&req->adapter->ccw_device->dev,
1582 "Opening WKA port 0x%x failed\n", wka_port->d_id);
Christof Schmittdceab652009-05-15 13:18:18 +02001583 /* fall through */
Swen Schillig5ab944f2008-10-01 12:42:17 +02001584 case FSF_ADAPTER_STATUS_AVAILABLE:
1585 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Christof Schmittbd0072e2009-11-24 16:54:11 +01001586 wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001587 break;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001588 case FSF_GOOD:
1589 wka_port->handle = header->port_handle;
Swen Schillig27f492c2009-07-13 15:06:13 +02001590 /* fall through */
1591 case FSF_PORT_ALREADY_OPEN:
Christof Schmittbd0072e2009-11-24 16:54:11 +01001592 wka_port->status = ZFCP_FC_WKA_PORT_ONLINE;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001593 }
1594out:
1595 wake_up(&wka_port->completion_wq);
1596}
1597
1598/**
1599 * zfcp_fsf_open_wka_port - create and send open wka-port request
Christof Schmittbd0072e2009-11-24 16:54:11 +01001600 * @wka_port: pointer to struct zfcp_fc_wka_port
Swen Schillig5ab944f2008-10-01 12:42:17 +02001601 * Returns: 0 on success, error otherwise
1602 */
Christof Schmittbd0072e2009-11-24 16:54:11 +01001603int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001604{
Swen Schillig564e1c82009-08-18 15:43:19 +02001605 struct zfcp_qdio *qdio = wka_port->adapter->qdio;
Steffen Maier2dfa6682017-02-08 15:34:22 +01001606 struct zfcp_fsf_req *req;
Benjamin Blockd85e8302019-07-02 23:02:01 +02001607 unsigned long req_id = 0;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001608 int retval = -EIO;
1609
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001610 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001611 if (zfcp_qdio_sbal_get(qdio))
Swen Schillig5ab944f2008-10-01 12:42:17 +02001612 goto out;
1613
Swen Schillig564e1c82009-08-18 15:43:19 +02001614 req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
Jan Glauber3ec908782011-06-06 14:14:40 +02001615 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001616 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001617
Tobias Klauser4e7d7af2011-02-22 19:54:38 +01001618 if (IS_ERR(req)) {
Swen Schillig5ab944f2008-10-01 12:42:17 +02001619 retval = PTR_ERR(req);
1620 goto out;
1621 }
1622
Swen Schillig09a46c62009-08-18 15:43:16 +02001623 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001624 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001625
1626 req->handler = zfcp_fsf_open_wka_port_handler;
Christof Schmitt800c0ca2009-11-24 16:54:12 +01001627 hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001628 req->data = wka_port;
1629
Benjamin Blockd85e8302019-07-02 23:02:01 +02001630 req_id = req->req_id;
1631
Swen Schillig5ab944f2008-10-01 12:42:17 +02001632 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1633 retval = zfcp_fsf_req_send(req);
1634 if (retval)
1635 zfcp_fsf_req_free(req);
1636out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001637 spin_unlock_irq(&qdio->req_q_lock);
Steffen Maier2dfa6682017-02-08 15:34:22 +01001638 if (!retval)
Benjamin Blockd85e8302019-07-02 23:02:01 +02001639 zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req_id);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001640 return retval;
1641}
1642
1643static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
1644{
Christof Schmittbd0072e2009-11-24 16:54:11 +01001645 struct zfcp_fc_wka_port *wka_port = req->data;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001646
1647 if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
1648 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligea4a3a62010-12-02 15:16:16 +01001649 zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1");
Swen Schillig5ab944f2008-10-01 12:42:17 +02001650 }
1651
Christof Schmittbd0072e2009-11-24 16:54:11 +01001652 wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001653 wake_up(&wka_port->completion_wq);
1654}
1655
1656/**
1657 * zfcp_fsf_close_wka_port - create and send close wka port request
Christof Schmittbd0072e2009-11-24 16:54:11 +01001658 * @wka_port: WKA port to open
Swen Schillig5ab944f2008-10-01 12:42:17 +02001659 * Returns: 0 on success, error otherwise
1660 */
Christof Schmittbd0072e2009-11-24 16:54:11 +01001661int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001662{
Swen Schillig564e1c82009-08-18 15:43:19 +02001663 struct zfcp_qdio *qdio = wka_port->adapter->qdio;
Steffen Maier2dfa6682017-02-08 15:34:22 +01001664 struct zfcp_fsf_req *req;
Benjamin Blockd85e8302019-07-02 23:02:01 +02001665 unsigned long req_id = 0;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001666 int retval = -EIO;
1667
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001668 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001669 if (zfcp_qdio_sbal_get(qdio))
Swen Schillig5ab944f2008-10-01 12:42:17 +02001670 goto out;
1671
Swen Schillig564e1c82009-08-18 15:43:19 +02001672 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
Jan Glauber3ec908782011-06-06 14:14:40 +02001673 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001674 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001675
Tobias Klauser4e7d7af2011-02-22 19:54:38 +01001676 if (IS_ERR(req)) {
Swen Schillig5ab944f2008-10-01 12:42:17 +02001677 retval = PTR_ERR(req);
1678 goto out;
1679 }
1680
Swen Schillig09a46c62009-08-18 15:43:16 +02001681 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001682 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001683
1684 req->handler = zfcp_fsf_close_wka_port_handler;
1685 req->data = wka_port;
1686 req->qtcb->header.port_handle = wka_port->handle;
1687
Benjamin Blockd85e8302019-07-02 23:02:01 +02001688 req_id = req->req_id;
1689
Swen Schillig5ab944f2008-10-01 12:42:17 +02001690 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1691 retval = zfcp_fsf_req_send(req);
1692 if (retval)
1693 zfcp_fsf_req_free(req);
1694out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001695 spin_unlock_irq(&qdio->req_q_lock);
Steffen Maier2dfa6682017-02-08 15:34:22 +01001696 if (!retval)
Benjamin Blockd85e8302019-07-02 23:02:01 +02001697 zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req_id);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001698 return retval;
1699}
1700
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001701static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001703 struct zfcp_port *port = req->data;
1704 struct fsf_qtcb_header *header = &req->qtcb->header;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001705 struct scsi_device *sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001707 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Christof Schmitta5b11dd2009-03-02 13:08:54 +01001708 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 switch (header->fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +01001712 zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001713 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 case FSF_PORT_BOXED:
Christof Schmitt5c815d12008-03-10 16:18:54 +01001716 /* can't use generic zfcp_erp_modify_port_status because
1717 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001718 atomic_andnot(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Christof Schmittb62a8d92010-09-08 14:39:55 +02001719 shost_for_each_device(sdev, port->adapter->scsi_host)
1720 if (sdev_to_zfcp(sdev)->port == port)
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001721 atomic_andnot(ZFCP_STATUS_COMMON_OPEN,
Christof Schmittb62a8d92010-09-08 14:39:55 +02001722 &sdev_to_zfcp(sdev)->status);
Swen Schilligedaed852010-09-08 14:40:01 +02001723 zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED);
1724 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schilligea4a3a62010-12-02 15:16:16 +01001725 "fscpph2");
Christof Schmitt4c571c62009-11-24 16:54:15 +01001726 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 switch (header->fsf_status_qual.word[0]) {
1730 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001731 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001733 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 /* can't use generic zfcp_erp_modify_port_status because
1739 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
1740 */
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001741 atomic_andnot(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Christof Schmittb62a8d92010-09-08 14:39:55 +02001742 shost_for_each_device(sdev, port->adapter->scsi_host)
1743 if (sdev_to_zfcp(sdev)->port == port)
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001744 atomic_andnot(ZFCP_STATUS_COMMON_OPEN,
Christof Schmittb62a8d92010-09-08 14:39:55 +02001745 &sdev_to_zfcp(sdev)->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748}
1749
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001750/**
1751 * zfcp_fsf_close_physical_port - close physical port
1752 * @erp_action: pointer to struct zfcp_erp_action
1753 * Returns: 0 on success
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001755int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
Swen Schillig564e1c82009-08-18 15:43:19 +02001757 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001758 struct zfcp_fsf_req *req;
1759 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001761 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001762 if (zfcp_qdio_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
Swen Schillig564e1c82009-08-18 15:43:19 +02001765 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT,
Jan Glauber3ec908782011-06-06 14:14:40 +02001766 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001767 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001768
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001769 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001770 retval = PTR_ERR(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 goto out;
1772 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001773
Swen Schillig09a46c62009-08-18 15:43:16 +02001774 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001775 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001776
1777 req->data = erp_action->port;
1778 req->qtcb->header.port_handle = erp_action->port->handle;
1779 req->erp_action = erp_action;
1780 req->handler = zfcp_fsf_close_physical_port_handler;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001781 erp_action->fsf_req_id = req->req_id;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001782
Christof Schmitt287ac012008-07-02 10:56:40 +02001783 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001784 retval = zfcp_fsf_req_send(req);
1785 if (retval) {
1786 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001787 erp_action->fsf_req_id = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001788 }
1789out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001790 spin_unlock_irq(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 return retval;
1792}
1793
Christof Schmittb62a8d92010-09-08 14:39:55 +02001794static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001796 struct zfcp_adapter *adapter = req->adapter;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001797 struct scsi_device *sdev = req->data;
Martin Peschked436de82012-09-04 15:23:36 +02001798 struct zfcp_scsi_dev *zfcp_sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001799 struct fsf_qtcb_header *header = &req->qtcb->header;
Martin Peschke663e0892013-04-26 16:13:54 +02001800 union fsf_status_qual *qual = &header->fsf_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001802 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001803 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Martin Peschked436de82012-09-04 15:23:36 +02001805 zfcp_sdev = sdev_to_zfcp(sdev);
1806
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001807 atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Martin Peschke663e0892013-04-26 16:13:54 +02001808 ZFCP_STATUS_COMMON_ACCESS_BOXED,
Christof Schmittb62a8d92010-09-08 14:39:55 +02001809 &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 switch (header->fsf_status) {
1812
1813 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +01001814 zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001815 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 case FSF_LUN_ALREADY_OPEN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 case FSF_PORT_BOXED:
Swen Schilligedaed852010-09-08 14:40:01 +02001819 zfcp_erp_set_port_status(zfcp_sdev->port,
1820 ZFCP_STATUS_COMMON_ACCESS_BOXED);
1821 zfcp_erp_port_reopen(zfcp_sdev->port,
Swen Schilligea4a3a62010-12-02 15:16:16 +01001822 ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2");
Christof Schmitt4c571c62009-11-24 16:54:15 +01001823 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 case FSF_LUN_SHARING_VIOLATION:
Martin Peschke663e0892013-04-26 16:13:54 +02001826 if (qual->word[0])
1827 dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev,
1828 "LUN 0x%Lx on port 0x%Lx is already in "
1829 "use by CSS%d, MIF Image ID %x\n",
1830 zfcp_scsi_dev_lun(sdev),
1831 (unsigned long long)zfcp_sdev->port->wwpn,
1832 qual->fsf_queue_designator.cssid,
1833 qual->fsf_queue_designator.hla);
1834 zfcp_erp_set_lun_status(sdev,
1835 ZFCP_STATUS_COMMON_ERP_FAILED |
1836 ZFCP_STATUS_COMMON_ACCESS_DENIED);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001837 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001840 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001841 "No handle is available for LUN "
1842 "0x%016Lx on port 0x%016Lx\n",
Christof Schmittb62a8d92010-09-08 14:39:55 +02001843 (unsigned long long)zfcp_scsi_dev_lun(sdev),
1844 (unsigned long long)zfcp_sdev->port->wwpn);
Swen Schilligedaed852010-09-08 14:40:01 +02001845 zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001846 /* fall through */
1847 case FSF_INVALID_COMMAND_OPTION:
1848 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 switch (header->fsf_status_qual.word[0]) {
1852 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Christof Schmittb62a8d92010-09-08 14:39:55 +02001853 zfcp_fc_test_link(zfcp_sdev->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001854 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001856 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
1859 break;
1860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 case FSF_GOOD:
Christof Schmittb62a8d92010-09-08 14:39:55 +02001862 zfcp_sdev->lun_handle = header->lun_handle;
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001863 atomic_or(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02001869 * zfcp_fsf_open_lun - open LUN
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001870 * @erp_action: pointer to struct zfcp_erp_action
1871 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001873int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001875 struct zfcp_adapter *adapter = erp_action->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +02001876 struct zfcp_qdio *qdio = adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001877 struct zfcp_fsf_req *req;
1878 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001880 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001881 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001882 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
Swen Schillig564e1c82009-08-18 15:43:19 +02001884 req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN,
Jan Glauber3ec908782011-06-06 14:14:40 +02001885 SBAL_SFLAGS0_TYPE_READ,
Swen Schilliga4623c42009-08-18 15:43:15 +02001886 adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001887
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001888 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001889 retval = PTR_ERR(req);
1890 goto out;
Christof Schmittba172422007-12-20 12:30:26 +01001891 }
1892
Swen Schillig09a46c62009-08-18 15:43:16 +02001893 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001894 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001896 req->qtcb->header.port_handle = erp_action->port->handle;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001897 req->qtcb->bottom.support.fcp_lun = zfcp_scsi_dev_lun(erp_action->sdev);
1898 req->handler = zfcp_fsf_open_lun_handler;
1899 req->data = erp_action->sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001900 req->erp_action = erp_action;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001901 erp_action->fsf_req_id = req->req_id;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001902
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001903 if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
1904 req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Christof Schmitt287ac012008-07-02 10:56:40 +02001906 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001907 retval = zfcp_fsf_req_send(req);
1908 if (retval) {
1909 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001910 erp_action->fsf_req_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001912out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001913 spin_unlock_irq(&qdio->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 return retval;
1915}
1916
Christof Schmittb62a8d92010-09-08 14:39:55 +02001917static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001919 struct scsi_device *sdev = req->data;
Martin Peschked436de82012-09-04 15:23:36 +02001920 struct zfcp_scsi_dev *zfcp_sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001921
1922 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001923 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001924
Martin Peschked436de82012-09-04 15:23:36 +02001925 zfcp_sdev = sdev_to_zfcp(sdev);
1926
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001927 switch (req->qtcb->header.fsf_status) {
1928 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +01001929 zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001930 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1931 break;
1932 case FSF_LUN_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +01001933 zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001934 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1935 break;
1936 case FSF_PORT_BOXED:
Swen Schilligedaed852010-09-08 14:40:01 +02001937 zfcp_erp_set_port_status(zfcp_sdev->port,
1938 ZFCP_STATUS_COMMON_ACCESS_BOXED);
1939 zfcp_erp_port_reopen(zfcp_sdev->port,
Swen Schilligea4a3a62010-12-02 15:16:16 +01001940 ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3");
Christof Schmitt4c571c62009-11-24 16:54:15 +01001941 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001942 break;
1943 case FSF_ADAPTER_STATUS_AVAILABLE:
1944 switch (req->qtcb->header.fsf_status_qual.word[0]) {
1945 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Christof Schmittb62a8d92010-09-08 14:39:55 +02001946 zfcp_fc_test_link(zfcp_sdev->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001947 /* fall through */
1948 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1949 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1950 break;
1951 }
1952 break;
1953 case FSF_GOOD:
Peter Zijlstra805de8f42015-04-24 01:12:32 +02001954 atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001955 break;
1956 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001957}
1958
1959/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02001960 * zfcp_fsf_close_LUN - close LUN
1961 * @erp_action: pointer to erp_action triggering the "close LUN"
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001962 * Returns: 0 on success, error otherwise
1963 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001964int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001965{
Swen Schillig564e1c82009-08-18 15:43:19 +02001966 struct zfcp_qdio *qdio = erp_action->adapter->qdio;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001967 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001968 struct zfcp_fsf_req *req;
1969 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
Christof Schmitt44a24cb2010-09-08 14:39:57 +02001971 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02001972 if (zfcp_qdio_sbal_get(qdio))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02001974
Swen Schillig564e1c82009-08-18 15:43:19 +02001975 req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN,
Jan Glauber3ec908782011-06-06 14:14:40 +02001976 SBAL_SFLAGS0_TYPE_READ,
Swen Schillig564e1c82009-08-18 15:43:19 +02001977 qdio->adapter->pool.erp_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02001978
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001979 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001980 retval = PTR_ERR(req);
1981 goto out;
1982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
Swen Schillig09a46c62009-08-18 15:43:16 +02001984 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Christof Schmitt1674b402010-04-30 18:09:34 +02001985 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001987 req->qtcb->header.port_handle = erp_action->port->handle;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001988 req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
1989 req->handler = zfcp_fsf_close_lun_handler;
1990 req->data = erp_action->sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001991 req->erp_action = erp_action;
Christof Schmitte60a6d62010-02-17 11:18:49 +01001992 erp_action->fsf_req_id = req->req_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Christof Schmitt287ac012008-07-02 10:56:40 +02001994 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001995 retval = zfcp_fsf_req_send(req);
1996 if (retval) {
1997 zfcp_fsf_req_free(req);
Christof Schmitte60a6d62010-02-17 11:18:49 +01001998 erp_action->fsf_req_id = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001999 }
2000out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02002001 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002002 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003}
2004
Christof Schmittc9615852008-05-06 11:00:05 +02002005static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
2006{
2007 lat_rec->sum += lat;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002008 lat_rec->min = min(lat_rec->min, lat);
2009 lat_rec->max = max(lat_rec->max, lat);
Christof Schmittc9615852008-05-06 11:00:05 +02002010}
2011
Christof Schmittd9742b42009-11-24 16:54:03 +01002012static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
Christof Schmittc9615852008-05-06 11:00:05 +02002013{
Christof Schmittd9742b42009-11-24 16:54:03 +01002014 struct fsf_qual_latency_info *lat_in;
2015 struct latency_cont *lat = NULL;
Martin Peschked436de82012-09-04 15:23:36 +02002016 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmittd9742b42009-11-24 16:54:03 +01002017 struct zfcp_blk_drv_data blktrc;
2018 int ticks = req->adapter->timer_ticks;
Christof Schmittc9615852008-05-06 11:00:05 +02002019
Christof Schmittd9742b42009-11-24 16:54:03 +01002020 lat_in = &req->qtcb->prefix.prot_status_qual.latency_info;
Christof Schmittc9615852008-05-06 11:00:05 +02002021
Christof Schmittd9742b42009-11-24 16:54:03 +01002022 blktrc.flags = 0;
2023 blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
2024 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
2025 blktrc.flags |= ZFCP_BLK_REQ_ERROR;
Swen Schillig706eca42010-07-16 15:37:38 +02002026 blktrc.inb_usage = 0;
Christof Schmitt34c2b712010-02-17 11:18:59 +01002027 blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
Christof Schmittd9742b42009-11-24 16:54:03 +01002028
Christof Schmitt5bbf2972010-04-01 13:04:08 +02002029 if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
2030 !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
Martin Peschked436de82012-09-04 15:23:36 +02002031 zfcp_sdev = sdev_to_zfcp(scsi->device);
Christof Schmittd9742b42009-11-24 16:54:03 +01002032 blktrc.flags |= ZFCP_BLK_LAT_VALID;
2033 blktrc.channel_lat = lat_in->channel_lat * ticks;
2034 blktrc.fabric_lat = lat_in->fabric_lat * ticks;
2035
2036 switch (req->qtcb->bottom.io.data_direction) {
Felix Beckef3eb712010-07-16 15:37:42 +02002037 case FSF_DATADIR_DIF_READ_STRIP:
2038 case FSF_DATADIR_DIF_READ_CONVERT:
Christof Schmittd9742b42009-11-24 16:54:03 +01002039 case FSF_DATADIR_READ:
Christof Schmittb62a8d92010-09-08 14:39:55 +02002040 lat = &zfcp_sdev->latencies.read;
Christof Schmittd9742b42009-11-24 16:54:03 +01002041 break;
Felix Beckef3eb712010-07-16 15:37:42 +02002042 case FSF_DATADIR_DIF_WRITE_INSERT:
2043 case FSF_DATADIR_DIF_WRITE_CONVERT:
Christof Schmittd9742b42009-11-24 16:54:03 +01002044 case FSF_DATADIR_WRITE:
Christof Schmittb62a8d92010-09-08 14:39:55 +02002045 lat = &zfcp_sdev->latencies.write;
Christof Schmittd9742b42009-11-24 16:54:03 +01002046 break;
2047 case FSF_DATADIR_CMND:
Christof Schmittb62a8d92010-09-08 14:39:55 +02002048 lat = &zfcp_sdev->latencies.cmd;
Christof Schmittd9742b42009-11-24 16:54:03 +01002049 break;
2050 }
2051
2052 if (lat) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02002053 spin_lock(&zfcp_sdev->latencies.lock);
Christof Schmittd9742b42009-11-24 16:54:03 +01002054 zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat);
2055 zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat);
2056 lat->counter++;
Christof Schmittb62a8d92010-09-08 14:39:55 +02002057 spin_unlock(&zfcp_sdev->latencies.lock);
Christof Schmittd9742b42009-11-24 16:54:03 +01002058 }
Christof Schmittc9615852008-05-06 11:00:05 +02002059 }
2060
Christof Schmittd9742b42009-11-24 16:54:03 +01002061 blk_add_driver_data(scsi->request->q, scsi->request, &blktrc,
2062 sizeof(blktrc));
Christof Schmittc9615852008-05-06 11:00:05 +02002063}
2064
Steffen Maier266883f2018-05-17 19:14:51 +02002065/**
2066 * zfcp_fsf_fcp_handler_common() - FCP response handler common to I/O and TMF.
2067 * @req: Pointer to FSF request.
2068 * @sdev: Pointer to SCSI device as request context.
2069 */
2070static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req,
2071 struct scsi_device *sdev)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002072{
Martin Peschked436de82012-09-04 15:23:36 +02002073 struct zfcp_scsi_dev *zfcp_sdev;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002074 struct fsf_qtcb_header *header = &req->qtcb->header;
2075
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002076 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
Christof Schmittc61b5362010-09-08 14:39:58 +02002077 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002078
Martin Peschked436de82012-09-04 15:23:36 +02002079 zfcp_sdev = sdev_to_zfcp(sdev);
2080
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002081 switch (header->fsf_status) {
2082 case FSF_HANDLE_MISMATCH:
2083 case FSF_PORT_HANDLE_NOT_VALID:
Steffen Maier266883f2018-05-17 19:14:51 +02002084 zfcp_erp_adapter_reopen(req->adapter, 0, "fssfch1");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002085 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2086 break;
2087 case FSF_FCPLUN_NOT_VALID:
2088 case FSF_LUN_HANDLE_NOT_VALID:
Swen Schilligea4a3a62010-12-02 15:16:16 +01002089 zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002090 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2091 break;
2092 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2093 zfcp_fsf_class_not_supp(req);
2094 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002095 case FSF_DIRECTION_INDICATOR_NOT_VALID:
2096 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittb62a8d92010-09-08 14:39:55 +02002097 "Incorrect direction %d, LUN 0x%016Lx on port "
Christof Schmittff3b24f2008-10-01 12:42:15 +02002098 "0x%016Lx closed\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002099 req->qtcb->bottom.io.data_direction,
Christof Schmittb62a8d92010-09-08 14:39:55 +02002100 (unsigned long long)zfcp_scsi_dev_lun(sdev),
2101 (unsigned long long)zfcp_sdev->port->wwpn);
Steffen Maier266883f2018-05-17 19:14:51 +02002102 zfcp_erp_adapter_shutdown(req->adapter, 0, "fssfch3");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002103 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2104 break;
2105 case FSF_CMND_LENGTH_NOT_VALID:
2106 dev_err(&req->adapter->ccw_device->dev,
Steffen Maier96f4a862018-11-08 15:44:47 +01002107 "Incorrect FCP_CMND length %d, FCP device closed\n",
2108 req->qtcb->bottom.io.fcp_cmnd_length);
Steffen Maier266883f2018-05-17 19:14:51 +02002109 zfcp_erp_adapter_shutdown(req->adapter, 0, "fssfch4");
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002110 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2111 break;
2112 case FSF_PORT_BOXED:
Swen Schilligedaed852010-09-08 14:40:01 +02002113 zfcp_erp_set_port_status(zfcp_sdev->port,
2114 ZFCP_STATUS_COMMON_ACCESS_BOXED);
2115 zfcp_erp_port_reopen(zfcp_sdev->port,
Swen Schilligea4a3a62010-12-02 15:16:16 +01002116 ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5");
Christof Schmitt4c571c62009-11-24 16:54:15 +01002117 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002118 break;
2119 case FSF_LUN_BOXED:
Swen Schilligedaed852010-09-08 14:40:01 +02002120 zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED);
2121 zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schilligea4a3a62010-12-02 15:16:16 +01002122 "fssfch6");
Christof Schmitt4c571c62009-11-24 16:54:15 +01002123 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002124 break;
2125 case FSF_ADAPTER_STATUS_AVAILABLE:
2126 if (header->fsf_status_qual.word[0] ==
2127 FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
Christof Schmittb62a8d92010-09-08 14:39:55 +02002128 zfcp_fc_test_link(zfcp_sdev->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002129 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2130 break;
2131 }
Christof Schmittc61b5362010-09-08 14:39:58 +02002132}
2133
2134static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req)
2135{
2136 struct scsi_cmnd *scpnt;
2137 struct fcp_resp_with_ext *fcp_rsp;
2138 unsigned long flags;
2139
Christof Schmittc61b5362010-09-08 14:39:58 +02002140 read_lock_irqsave(&req->adapter->abort_lock, flags);
2141
2142 scpnt = req->data;
2143 if (unlikely(!scpnt)) {
2144 read_unlock_irqrestore(&req->adapter->abort_lock, flags);
2145 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002146 }
Christof Schmittc61b5362010-09-08 14:39:58 +02002147
Steffen Maier266883f2018-05-17 19:14:51 +02002148 zfcp_fsf_fcp_handler_common(req, scpnt->device);
Swen Schillig5bfb2c32010-11-17 14:23:40 +01002149
Christof Schmittc61b5362010-09-08 14:39:58 +02002150 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
2151 set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED);
2152 goto skip_fsfstatus;
2153 }
2154
2155 switch (req->qtcb->header.fsf_status) {
2156 case FSF_INCONSISTENT_PROT_DATA:
2157 case FSF_INVALID_PROT_PARM:
2158 set_host_byte(scpnt, DID_ERROR);
2159 goto skip_fsfstatus;
2160 case FSF_BLOCK_GUARD_CHECK_FAILURE:
2161 zfcp_scsi_dif_sense_error(scpnt, 0x1);
2162 goto skip_fsfstatus;
2163 case FSF_APP_TAG_CHECK_FAILURE:
2164 zfcp_scsi_dif_sense_error(scpnt, 0x2);
2165 goto skip_fsfstatus;
2166 case FSF_REF_TAG_CHECK_FAILURE:
2167 zfcp_scsi_dif_sense_error(scpnt, 0x3);
2168 goto skip_fsfstatus;
2169 }
Steffen Maierdf00d7b2017-07-28 12:31:01 +02002170 BUILD_BUG_ON(sizeof(struct fcp_resp_with_ext) > FSF_FCP_RSP_SIZE);
2171 fcp_rsp = &req->qtcb->bottom.io.fcp_rsp.iu;
Christof Schmittc61b5362010-09-08 14:39:58 +02002172 zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
2173
2174skip_fsfstatus:
2175 zfcp_fsf_req_trace(req, scpnt);
Swen Schillig250a1352010-12-02 15:16:15 +01002176 zfcp_dbf_scsi_result(scpnt, req);
Christof Schmittc61b5362010-09-08 14:39:58 +02002177
2178 scpnt->host_scribble = NULL;
2179 (scpnt->scsi_done) (scpnt);
2180 /*
2181 * We must hold this lock until scsi_done has been called.
2182 * Otherwise we may call scsi_done after abort regarding this
2183 * command has completed.
2184 * Note: scsi_done must not block!
2185 */
2186 read_unlock_irqrestore(&req->adapter->abort_lock, flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002187}
2188
Felix Beckef3eb712010-07-16 15:37:42 +02002189static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
2190{
2191 switch (scsi_get_prot_op(scsi_cmnd)) {
2192 case SCSI_PROT_NORMAL:
2193 switch (scsi_cmnd->sc_data_direction) {
2194 case DMA_NONE:
2195 *data_dir = FSF_DATADIR_CMND;
2196 break;
2197 case DMA_FROM_DEVICE:
2198 *data_dir = FSF_DATADIR_READ;
2199 break;
2200 case DMA_TO_DEVICE:
2201 *data_dir = FSF_DATADIR_WRITE;
2202 break;
2203 case DMA_BIDIRECTIONAL:
2204 return -EINVAL;
2205 }
2206 break;
2207
2208 case SCSI_PROT_READ_STRIP:
2209 *data_dir = FSF_DATADIR_DIF_READ_STRIP;
2210 break;
2211 case SCSI_PROT_WRITE_INSERT:
2212 *data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
2213 break;
2214 case SCSI_PROT_READ_PASS:
2215 *data_dir = FSF_DATADIR_DIF_READ_CONVERT;
2216 break;
2217 case SCSI_PROT_WRITE_PASS:
2218 *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
2219 break;
2220 default:
2221 return -EINVAL;
2222 }
2223
2224 return 0;
2225}
2226
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002227/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02002228 * zfcp_fsf_fcp_cmnd - initiate an FCP command (for a SCSI command)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002229 * @scsi_cmnd: scsi command to be sent
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002230 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02002231int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002232{
2233 struct zfcp_fsf_req *req;
Christof Schmitt4318e082009-11-24 16:54:08 +01002234 struct fcp_cmnd *fcp_cmnd;
Jan Glauber3ec908782011-06-06 14:14:40 +02002235 u8 sbtype = SBAL_SFLAGS0_TYPE_READ;
Swen Schillig86a96682011-08-15 14:40:32 +02002236 int retval = -EIO;
Christof Schmittb62a8d92010-09-08 14:39:55 +02002237 struct scsi_device *sdev = scsi_cmnd->device;
2238 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
2239 struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
Swen Schillig564e1c82009-08-18 15:43:19 +02002240 struct zfcp_qdio *qdio = adapter->qdio;
Felix Beckef3eb712010-07-16 15:37:42 +02002241 struct fsf_qtcb_bottom_io *io;
Christof Schmitte55f8752010-11-18 14:53:18 +01002242 unsigned long flags;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002243
Christof Schmittb62a8d92010-09-08 14:39:55 +02002244 if (unlikely(!(atomic_read(&zfcp_sdev->status) &
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002245 ZFCP_STATUS_COMMON_UNBLOCKED)))
2246 return -EBUSY;
2247
Christof Schmitte55f8752010-11-18 14:53:18 +01002248 spin_lock_irqsave(&qdio->req_q_lock, flags);
Swen Schillig706eca42010-07-16 15:37:38 +02002249 if (atomic_read(&qdio->req_q_free) <= 0) {
Swen Schillig564e1c82009-08-18 15:43:19 +02002250 atomic_inc(&qdio->req_q_full);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002251 goto out;
Christof Schmitt8fdf30d2009-03-02 13:09:01 +01002252 }
Swen Schillig09a46c62009-08-18 15:43:16 +02002253
Christof Schmitt1674b402010-04-30 18:09:34 +02002254 if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE)
Jan Glauber3ec908782011-06-06 14:14:40 +02002255 sbtype = SBAL_SFLAGS0_TYPE_WRITE;
Christof Schmitt1674b402010-04-30 18:09:34 +02002256
Swen Schillig564e1c82009-08-18 15:43:19 +02002257 req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
Christof Schmitt1674b402010-04-30 18:09:34 +02002258 sbtype, adapter->pool.scsi_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02002259
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002260 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002261 retval = PTR_ERR(req);
2262 goto out;
2263 }
2264
Felix Beckef3eb712010-07-16 15:37:42 +02002265 scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2266
2267 io = &req->qtcb->bottom.io;
Swen Schillig09a46c62009-08-18 15:43:16 +02002268 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002269 req->data = scsi_cmnd;
Christof Schmittc61b5362010-09-08 14:39:58 +02002270 req->handler = zfcp_fsf_fcp_cmnd_handler;
Christof Schmittb62a8d92010-09-08 14:39:55 +02002271 req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
2272 req->qtcb->header.port_handle = zfcp_sdev->port->handle;
Felix Beckef3eb712010-07-16 15:37:42 +02002273 io->service_class = FSF_CLASS_3;
2274 io->fcp_cmnd_length = FCP_CMND_LEN;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002275
Felix Beckef3eb712010-07-16 15:37:42 +02002276 if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
2277 io->data_block_length = scsi_cmnd->device->sector_size;
2278 io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002279 }
2280
Steffen Maiercc405ac2011-08-15 14:40:30 +02002281 if (zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction))
2282 goto failed_scsi_cmnd;
Felix Beckef3eb712010-07-16 15:37:42 +02002283
Steffen Maierdf00d7b2017-07-28 12:31:01 +02002284 BUILD_BUG_ON(sizeof(struct fcp_cmnd) > FSF_FCP_CMND_SIZE);
2285 fcp_cmnd = &req->qtcb->bottom.io.fcp_cmnd.iu;
Steffen Maiere0116c92018-05-17 19:14:52 +02002286 zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002287
Steffen Maier71b8e452017-07-28 12:30:51 +02002288 if ((scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) &&
2289 scsi_prot_sg_count(scsi_cmnd)) {
Felix Beckef3eb712010-07-16 15:37:42 +02002290 zfcp_qdio_set_data_div(qdio, &req->qdio_req,
2291 scsi_prot_sg_count(scsi_cmnd));
Swen Schillig86a96682011-08-15 14:40:32 +02002292 retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
2293 scsi_prot_sglist(scsi_cmnd));
2294 if (retval)
2295 goto failed_scsi_cmnd;
2296 io->prot_data_length = zfcp_qdio_real_bytes(
Felix Beckef3eb712010-07-16 15:37:42 +02002297 scsi_prot_sglist(scsi_cmnd));
Felix Beckef3eb712010-07-16 15:37:42 +02002298 }
2299
Swen Schillig86a96682011-08-15 14:40:32 +02002300 retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
2301 scsi_sglist(scsi_cmnd));
2302 if (unlikely(retval))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002303 goto failed_scsi_cmnd;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002304
Felix Beckef3eb712010-07-16 15:37:42 +02002305 zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
Swen Schillig86a96682011-08-15 14:40:32 +02002306 if (zfcp_adapter_multi_buffer_active(adapter))
2307 zfcp_qdio_set_scount(qdio, &req->qdio_req);
Felix Beckef3eb712010-07-16 15:37:42 +02002308
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002309 retval = zfcp_fsf_req_send(req);
2310 if (unlikely(retval))
2311 goto failed_scsi_cmnd;
2312
2313 goto out;
2314
2315failed_scsi_cmnd:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002316 zfcp_fsf_req_free(req);
2317 scsi_cmnd->host_scribble = NULL;
2318out:
Christof Schmitte55f8752010-11-18 14:53:18 +01002319 spin_unlock_irqrestore(&qdio->req_q_lock, flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002320 return retval;
2321}
2322
Christof Schmittc61b5362010-09-08 14:39:58 +02002323static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req)
2324{
Steffen Maier266883f2018-05-17 19:14:51 +02002325 struct scsi_device *sdev = req->data;
Christof Schmittc61b5362010-09-08 14:39:58 +02002326 struct fcp_resp_with_ext *fcp_rsp;
2327 struct fcp_resp_rsp_info *rsp_info;
2328
Steffen Maier266883f2018-05-17 19:14:51 +02002329 zfcp_fsf_fcp_handler_common(req, sdev);
Christof Schmittc61b5362010-09-08 14:39:58 +02002330
Steffen Maierdf00d7b2017-07-28 12:31:01 +02002331 fcp_rsp = &req->qtcb->bottom.io.fcp_rsp.iu;
Christof Schmittc61b5362010-09-08 14:39:58 +02002332 rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
2333
2334 if ((rsp_info->rsp_code != FCP_TMF_CMPL) ||
2335 (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2336 req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
2337}
2338
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002339/**
Steffen Maier26f5fa92018-05-17 19:14:54 +02002340 * zfcp_fsf_fcp_task_mgmt() - Send SCSI task management command (TMF).
2341 * @sdev: Pointer to SCSI device to send the task management command to.
2342 * @tm_flags: Unsigned byte for task management flags.
2343 *
2344 * Return: On success pointer to struct zfcp_fsf_req, %NULL otherwise.
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002345 */
Steffen Maier26f5fa92018-05-17 19:14:54 +02002346struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_device *sdev,
Christof Schmittb62a8d92010-09-08 14:39:55 +02002347 u8 tm_flags)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002348{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002349 struct zfcp_fsf_req *req = NULL;
Christof Schmitt4318e082009-11-24 16:54:08 +01002350 struct fcp_cmnd *fcp_cmnd;
Steffen Maier39abb112018-05-17 19:14:53 +02002351 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
Christof Schmittb62a8d92010-09-08 14:39:55 +02002352 struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002353
Christof Schmittb62a8d92010-09-08 14:39:55 +02002354 if (unlikely(!(atomic_read(&zfcp_sdev->status) &
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002355 ZFCP_STATUS_COMMON_UNBLOCKED)))
2356 return NULL;
2357
Christof Schmitt44a24cb2010-09-08 14:39:57 +02002358 spin_lock_irq(&qdio->req_q_lock);
Christof Schmitt6b9e1522010-04-30 18:09:35 +02002359 if (zfcp_qdio_sbal_get(qdio))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002360 goto out;
Swen Schillig09a46c62009-08-18 15:43:16 +02002361
Swen Schillig564e1c82009-08-18 15:43:19 +02002362 req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
Jan Glauber3ec908782011-06-06 14:14:40 +02002363 SBAL_SFLAGS0_TYPE_WRITE,
Swen Schillig564e1c82009-08-18 15:43:19 +02002364 qdio->adapter->pool.scsi_req);
Swen Schillig09a46c62009-08-18 15:43:16 +02002365
Swen Schillig633528c2008-11-26 18:07:37 +01002366 if (IS_ERR(req)) {
2367 req = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002368 goto out;
Swen Schillig633528c2008-11-26 18:07:37 +01002369 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002370
Steffen Maier39abb112018-05-17 19:14:53 +02002371 req->data = sdev;
2372
Christof Schmittc61b5362010-09-08 14:39:58 +02002373 req->handler = zfcp_fsf_fcp_task_mgmt_handler;
Christof Schmittb62a8d92010-09-08 14:39:55 +02002374 req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
2375 req->qtcb->header.port_handle = zfcp_sdev->port->handle;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002376 req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2377 req->qtcb->bottom.io.service_class = FSF_CLASS_3;
Christof Schmitt4318e082009-11-24 16:54:08 +01002378 req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002379
Christof Schmitt1674b402010-04-30 18:09:34 +02002380 zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002381
Steffen Maierdf00d7b2017-07-28 12:31:01 +02002382 fcp_cmnd = &req->qtcb->bottom.io.fcp_cmnd.iu;
Steffen Maier39abb112018-05-17 19:14:53 +02002383 zfcp_fc_fcp_tm(fcp_cmnd, sdev, tm_flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002384
2385 zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2386 if (!zfcp_fsf_req_send(req))
2387 goto out;
2388
2389 zfcp_fsf_req_free(req);
2390 req = NULL;
2391out:
Christof Schmitt44a24cb2010-09-08 14:39:57 +02002392 spin_unlock_irq(&qdio->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002393 return req;
2394}
2395
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002396/**
2397 * zfcp_fsf_reqid_check - validate req_id contained in SBAL returned by QDIO
2398 * @adapter: pointer to struct zfcp_adapter
2399 * @sbal_idx: response queue index of SBAL to be processed
2400 */
Swen Schillig564e1c82009-08-18 15:43:19 +02002401void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002402{
Swen Schillig564e1c82009-08-18 15:43:19 +02002403 struct zfcp_adapter *adapter = qdio->adapter;
Swen Schillig706eca42010-07-16 15:37:38 +02002404 struct qdio_buffer *sbal = qdio->res_q[sbal_idx];
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002405 struct qdio_buffer_element *sbale;
2406 struct zfcp_fsf_req *fsf_req;
Christof Schmittb6bd2fb2010-02-17 11:18:50 +01002407 unsigned long req_id;
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002408 int idx;
2409
2410 for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) {
2411
2412 sbale = &sbal->element[idx];
2413 req_id = (unsigned long) sbale->addr;
Christof Schmittb6bd2fb2010-02-17 11:18:50 +01002414 fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002415
Christof Schmitt339f4f42010-07-16 15:37:43 +02002416 if (!fsf_req) {
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002417 /*
2418 * Unknown request means that we have potentially memory
2419 * corruption and must stop the machine immediately.
2420 */
Christof Schmitt339f4f42010-07-16 15:37:43 +02002421 zfcp_qdio_siosl(adapter);
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002422 panic("error: unknown req_id (%lx) on adapter %s.\n",
2423 req_id, dev_name(&adapter->ccw_device->dev));
Christof Schmitt339f4f42010-07-16 15:37:43 +02002424 }
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002425
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002426 zfcp_fsf_req_complete(fsf_req);
2427
Jan Glauber3ec908782011-06-06 14:14:40 +02002428 if (likely(sbale->eflags & SBAL_EFLAGS_LAST_ENTRY))
Swen Schilligbd63eaf2009-08-18 15:43:13 +02002429 break;
2430 }
2431}