zfcp_fsf.c revision 633528c304f20b5c2e3e04d48f620548ce08b12e
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt * zfcp device driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt * Implementation of FSF commands.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt * Copyright IBM Corporation 2002, 2008
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#include <linux/blktrace_api.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "zfcp_ext.h"
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_request_timeout_handler(unsigned long data)
13287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
14287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
15287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62,
16287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt				NULL);
17287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
18287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
19287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
20287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt				 unsigned long timeout)
21287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
22287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
23287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.data = (unsigned long) fsf_req->adapter;
24287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.expires = jiffies + timeout;
25287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	add_timer(&fsf_req->timer);
26287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
27287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
28287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req)
29287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
30287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	BUG_ON(!fsf_req->erp_action);
31287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.function = zfcp_erp_timeout_handler;
32287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
33287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.expires = jiffies + 30 * HZ;
34287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	add_timer(&fsf_req->timer);
35287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
36287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* association between FSF command and FSF QTCB type */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 fsf_qtcb_type[] = {
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND,
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND,
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND,
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND,
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND,
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
55553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
56c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	u16 subtable = table >> 16;
57553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	u16 rule = table & 0xffff;
58ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
59553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
60ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	if (subtable && subtable < ARRAY_SIZE(act_type))
61553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		dev_warn(&adapter->ccw_device->dev,
62ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "Access denied according to ACT rule type %s, "
63ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "rule %d\n", act_type[subtable], rule);
64553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
65553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
66553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
67553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					struct zfcp_port *port)
68553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
69553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct fsf_qtcb_header *header = &req->qtcb->header;
70553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	dev_warn(&req->adapter->ccw_device->dev,
71ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		 "Access denied to port 0x%016Lx\n",
727ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		 (unsigned long long)port->wwpn);
73553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
74553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
75553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_erp_port_access_denied(port, 55, req);
76553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
77553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
78553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
79553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
80553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					struct zfcp_unit *unit)
81553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
82553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct fsf_qtcb_header *header = &req->qtcb->header;
83553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	dev_warn(&req->adapter->ccw_device->dev,
84ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		 "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
857ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		 (unsigned long long)unit->fcp_lun,
867ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		 (unsigned long long)unit->port->wwpn);
87553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
88553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
89553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_erp_unit_access_denied(unit, 59, req);
90553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
91553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
92553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
93553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
94553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
95ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	dev_err(&req->adapter->ccw_device->dev, "FCP device not "
96ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		"operational because of an unsupported FC class\n");
97553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req);
98553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
99553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
100553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
101c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
102c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_free - free memory used by fsf request
103c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_req: pointer to struct zfcp_fsf_req
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
105c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligvoid zfcp_fsf_req_free(struct zfcp_fsf_req *req)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
107c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->pool)) {
108c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		mempool_free(req, req->pool);
109dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
110dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
111dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens
112c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb) {
113c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req);
114dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
115dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
118c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
120c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
121c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
122869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Never ever call this without shutting down the adapter first.
123869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Otherwise the adapter would continue using and corrupting s390 storage.
124869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Included BUG_ON() call to ensure this is done.
125869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * ERP is supposed to be the only user of this function.
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1276fcc47111ae14f284007e1b9a5002babb01d913cSwen Schilligvoid zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
129c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req, *tmp;
130fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	unsigned long flags;
1316fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig	LIST_HEAD(remove_queue);
132869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	unsigned int i;
133fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
134c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
135fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_lock_irqsave(&adapter->req_list_lock, flags);
136869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	for (i = 0; i < REQUEST_LIST_SIZE; i++)
1376fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig		list_splice_init(&adapter->req_list[i], &remove_queue);
138fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
139fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
140c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_for_each_entry_safe(req, tmp, &remove_queue, list) {
141c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		list_del(&req->list);
142c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
143c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_complete(req);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
149c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
150c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port;
152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int d_id = sr_buf->d_id & ZFCP_DID_MASK;
153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned long flags;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&zfcp_data.config_lock, flags);
156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_for_each_entry(port, &adapter->port_list_head, list)
157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (port->d_id == d_id) {
158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			read_unlock_irqrestore(&zfcp_data.config_lock, flags);
159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			switch (sr_buf->status_subtype) {
160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_port_reopen(port, 0, 101, req);
162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				break;
163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			case FSF_STATUS_READ_SUB_ERROR_PORT:
164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_port_shutdown(port, 0, 122, req);
165c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				break;
166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			}
167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
168c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
169c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
172c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
173c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					 struct fsf_link_down_info *link_down)
174aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin{
175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
176698ec01635819c5ae60090bb4efcbeffc41642fbMartin Peschke
177c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
178ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin		return;
179ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
180ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin	atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
181ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!link_down)
1832f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		goto out;
184ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
185aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (link_down->error_code) {
186aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_LIGHT:
187c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
188ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "There is no light signal from the local "
189ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "fibre channel cable\n");
190aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
191aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WRAP_PLUG:
192c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
193ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "There is a wrap plug instead of a fibre "
194ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "channel cable\n");
195aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
196aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP:
197c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
198ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The adjacent fibre channel node does not "
199ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "support FCP\n");
200aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
201aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FIRMWARE_UPDATE:
202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
203ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP device is suspended because of a "
204ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "firmware update\n");
205553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		break;
206aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_INVALID_WWPN:
207c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
208ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP device detected a WWPN that is "
209ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "duplicate or not valid\n");
210aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
211aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
213ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The fibre channel fabric does not support NPIV\n");
214aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
215aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP_RESOURCES:
216c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
217ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP adapter cannot support more NPIV ports\n");
218aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
219aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
220c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
221ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The adjacent switch cannot support "
222ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "more NPIV ports\n");
223aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
224aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
225c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
226ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP adapter could not log in to the "
227ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "fibre channel fabric\n");
228aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
229aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
230c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
231ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The WWPN assignment file on the FCP adapter "
232ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been damaged\n");
233aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
234aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
235c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
236ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The mode table on the FCP adapter "
237ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been damaged\n");
238aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
239aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
240c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
241ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "All NPIV ports on the FCP adapter have "
242ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "been assigned\n");
243aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
244aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	default:
245c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
246ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The link between the FCP adapter and "
247ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "the FC fabric is down\n");
248aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
249c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
250c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_erp_adapter_failed(adapter, id, req);
251aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin}
252aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_link_down_info *ldi =
257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		(struct fsf_link_down_info *) &sr_buf->payload;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (sr_buf->status_subtype) {
260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 38, ldi);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_FDISC_FAILED:
264c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 39, ldi);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
266c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 40, NULL);
268c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	};
269c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
272c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
273c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
274c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf);
278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		mempool_free(sr_buf, adapter->pool.data_status_read);
279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
281c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
283c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
285c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (sr_buf->status_type) {
286c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_PORT_CLOSED:
287c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_port_closed(req);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
289c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_INCOMING_ELS:
290c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fc_incoming_els(req);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
292c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
294c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
295ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		dev_warn(&adapter->ccw_device->dev,
296ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The error threshold for checksum statistics "
297ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been exceeded\n");
29857069386699994c3e67042fc4928c418f3a39e01Swen Schillig		zfcp_hba_dbf_event_berr(adapter, req);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_LINK_DOWN:
301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_link_down(req);
302c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
303c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_LINK_UP:
304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_info(&adapter->ccw_device->dev,
305ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The local link has been restored\n");
306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* All ports should be marked as ready to run again */
307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_adapter_status(adapter, 30, NULL,
308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_STATUS_COMMON_RUNNING,
309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_SET);
310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter,
311c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_COMMON_ERP_FAILED,
313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					102, req);
314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
315c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_NOTIFICATION_LOST:
316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_adapter_access_changed(adapter, 135, req);
318c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
319c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			schedule_work(&adapter->scan_work);
320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
321c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_CFDC_UPDATED:
322c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_access_changed(adapter, 136, req);
323c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->adapter_features = sr_buf->payload.word[0];
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
332c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_inc(&adapter->stat_miss);
333b7f15f3c94196accac799727502ed88a029ae7efSwen Schillig	queue_work(zfcp_data.work_queue, &adapter->stat_work);
334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
337c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status_qual.word[0]) {
339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_FCP_RSP_AVAILABLE:
340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_NO_RETRY_POSSIBLE:
342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_COMMAND_ABORTED:
345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
347c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_NO_RECOM:
348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
349ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter reported a problem "
350ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"that cannot be recovered\n");
351c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req);
352c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* all non-return stats set FSFREQ_ERROR*/
355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
361c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
364c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_UNKNOWN_COMMAND:
365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
366ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter does not recognize the command 0x%x\n",
367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->header.fsf_command);
368c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req);
369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_fsfstatus_qual_eval(req);
373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
378c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
379c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
380c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
381c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_response(req);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
387c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->prefix.prot_status) {
392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_GOOD:
393c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_FSF_STATUS_PRESENTED:
394c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
395c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_QTCB_VERSION_ERROR:
396c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
397ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"QTCB version 0x%x not supported by FCP adapter "
398ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
399ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			psq->word[0], psq->word[1]);
400c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 117, req);
401c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
402c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_ERROR_STATE:
403c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_SEQ_NUMB_ERROR:
404c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 98, req);
405c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_RETRY;
406c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
407c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_UNSUPP_QTCB_TYPE:
408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
409ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The QTCB type is not supported by the FCP adapter\n");
410c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 118, req);
411c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_HOST_CONNECTION_INITIALIZING:
413c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
415c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
416c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_DUPLICATE_REQUEST_ID:
417c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
418ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%Lx is an ambiguous request identifier\n",
419c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(unsigned long long)qtcb->bottom.support.req_handle);
420c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 78, req);
421c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
422c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_LINK_DOWN:
423c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info);
424c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* FIXME: reopening adapter now? better wait for link up */
425c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 79, req);
426c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
427c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_REEST_QUEUE:
428c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* All ports should be marked as ready to run again */
429c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_adapter_status(adapter, 28, NULL,
430c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_STATUS_COMMON_RUNNING,
431c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_SET);
432c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter,
433c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
434c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_COMMON_ERP_FAILED, 99, req);
435c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
436c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
437c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
438ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%x is not a valid transfer protocol status\n",
439c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			qtcb->prefix.prot_status);
440c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 119, req);
441c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
442c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_complete - process completion of a FSF request
447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_req: The FSF request that has been completed.
448c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
449c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * When a request has been completed either from the FCP adapter,
450c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * or it has been dismissed due to a queue shutdown, this function
451c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * is called to process the completion status and trigger further
452c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * events related to the FSF request.
453c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig */
454c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligvoid zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
457c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_handler(req);
458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	del_timer(&req->timer);
462c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_protstatus_eval(req);
463c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_fsfstatus_eval(req);
464c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler(req);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->erp_action)
467287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt		zfcp_erp_notify(req->erp_action, 0);
468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
470c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
471c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* notify initiator waiting for the requests completion */
474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * FIXME: Race! We must not access fsf_req here as it might have been
476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * flag. It's an improbable case. But, we have the same paranoia for
478c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * the cleanup flag already.
479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * Might better be handled using complete()?
480c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * (setting the flag and doing wakeup ought to be atomic
481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *  with regard to checking the flag as long as waitqueue is
482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *  part of the to be released structure)
483c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
484c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wake_up(&req->completion_wq);
485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_config *bottom;
490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
491c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.config;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->data)
496c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(req->data, bottom, sizeof(*bottom));
497c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
500c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
501c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_speed(shost) = bottom->fc_link_speed;
502c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->hydra_version = bottom->adapter_type;
505c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->timer_ticks = bottom->timer_interval;
506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
507c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (fc_host_permanent_port_name(shost) == -1)
508c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
509c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
510c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (bottom->fc_topology) {
511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_P2P:
512c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
514c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
515c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_PTP;
516c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
517c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_FABRIC:
518c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
519c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
520c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_AL:
521c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
522c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
523c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
524ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Unknown or unsupported arbitrated loop "
525ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"fibre channel topology detected\n");
526ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
527c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
529c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
533c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
534553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
535553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct zfcp_adapter *adapter = req->adapter;
536c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
539553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->fsf_lic_version = bottom->lic_version;
544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->adapter_features = bottom->adapter_features;
545c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->connection_features = bottom->connection_features;
546c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_wwpn = 0;
547c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_wwnn = 0;
548c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_d_id = 0;
5498a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
550c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
551c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
552c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (zfcp_fsf_exchange_config_evaluate(req))
553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
555c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
556c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
557ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"FCP adapter maximum QTCB size (%d bytes) "
558ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"is too small\n",
559ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				bottom->max_qtcb_size);
560c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_adapter_shutdown(adapter, 0, 129, req);
561c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
562c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
563c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
564c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
566c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
567c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_node_name(shost) = 0;
568c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_name(shost) = 0;
569c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_id(shost) = 0;
570c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
571c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
572c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->hydra_version = 0;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
574c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
575c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
577c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 42,
578c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
580c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
581c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 130, req);
582c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
583c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
585c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
586c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->hardware_version = bottom->hardware_version;
587c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(fc_host_serial_number(shost), bottom->serial_number,
588c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       min(FC_SERIAL_NUMBER_SIZE, 17));
589c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		EBCASC(fc_host_serial_number(shost),
590c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       min(FC_SERIAL_NUMBER_SIZE, 17));
591c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
593c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
594c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
595ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter only supports newer "
596ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"control block versions\n");
597c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 125, req);
598c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
599c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
600c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
601c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
602ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter only supports older "
603ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"control block versions\n");
604c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 126, req);
605c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
606c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
608c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
609c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
610c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
611c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port;
612c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
614c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->data)
615c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(req->data, bottom, sizeof(*bottom));
6169eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin
617c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
618c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = bottom->wwpn;
619c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
620c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
621c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
622c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_supported_speeds(shost) = bottom->supported_speed;
623c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
625c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
626c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
627c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
628c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
629c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
630c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
631c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
632c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
633c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
634c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
635c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
636c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
637c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
638c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 43,
639c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
640aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
642c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
643d26ab06ede83287f99067fee3034c5455a75faf9Swen Schillig
6440406289ed57955860a4f8d744a14f4c819260ce4Christof Schmittstatic int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter)
645c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
6460406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	struct zfcp_qdio_queue *req_q = &adapter->req_q;
6470406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt
6480406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
6490406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	if (atomic_read(&req_q->count))
650c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 1;
6510406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
652c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6552450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Rasplstatic int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
6562450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl{
6572450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	unsigned int count = atomic_read(&adapter->req_q.count);
6582450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!count)
6592450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
6602450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	return count > 0;
6612450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl}
6622450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl
663c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
664c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
665c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	long ret;
666c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
6670406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
668c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = wait_event_interruptible_timeout(adapter->request_wq,
6690406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt					zfcp_fsf_sbal_check(adapter), 5 * HZ);
670c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret > 0)
671c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 0;
6722450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!ret)
6732450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
674c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
6750406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
676c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return -EIO;
677c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
678c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
679c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool)
680c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
681c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
682c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = mempool_alloc(pool, GFP_ATOMIC);
683c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!req)
684c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
685c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(req, 0, sizeof(*req));
68688f2a977870af655296a682fe2a58c822cd25bb2Christof Schmitt	req->pool = pool;
687c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
688c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
689c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
690c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool)
691c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
692c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req_qtcb *qtcb;
693c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
694c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(pool))
695c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = mempool_alloc(pool, GFP_ATOMIC);
696c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
697c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
698c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					GFP_ATOMIC);
699c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!qtcb))
700c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
701c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
702c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(qtcb, 0, sizeof(*qtcb));
703c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.qtcb = &qtcb->qtcb;
704c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.pool = pool;
705c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
706c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return &qtcb->fsf_req;
707c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
708c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
709c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
710c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						u32 fsf_cmd, int req_flags,
711c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						mempool_t *pool)
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
71344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
715c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
716c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
717951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
718c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req_flags & ZFCP_REQ_NO_QTCB)
719c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_noqtcb(pool);
720c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
721c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_qtcb(pool);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
723c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!req))
724c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
726c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->req_no == 0)
727c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->req_no++;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
729c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	INIT_LIST_HEAD(&req->list);
730c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_timer(&req->timer);
731c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_waitqueue_head(&req->completion_wq);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
733c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->adapter = adapter;
734c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->fsf_command = fsf_cmd;
735c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->req_id = adapter->req_no++;
736c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_number = 1;
737c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_first = req_q->first;
738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_last = req_q->first;
739c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 1;
740c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
741c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
742c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].addr = (void *) req->req_id;
743c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
744c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
745c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->qtcb)) {
746c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no;
747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_id = req->req_id;
748c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.ulp_info = 26;
749c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
750c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
751c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.req_handle = req->req_id;
752c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.fsf_command = req->fsf_command;
753c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->seq_no = adapter->fsf_req_seq_no;
754c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
755c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].addr = (void *) req->qtcb;
756c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].length = sizeof(struct fsf_qtcb);
757c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
758c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
759c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
760c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
761c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
762c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
763951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
764c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
765c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
767c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
770c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
771c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
772c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
77345316a86a67934ab499dcfac44c91aa8f39c4c78Heiko Carstens	unsigned long flags;
774c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int idx;
775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
776c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* put allocated FSF request into hash table */
77745316a86a67934ab499dcfac44c91aa8f39c4c78Heiko Carstens	spin_lock_irqsave(&adapter->req_list_lock, flags);
778c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	idx = zfcp_reqlist_hash(req->req_id);
779c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_add_tail(&req->list, &adapter->req_list[idx]);
78045316a86a67934ab499dcfac44c91aa8f39c4c78Heiko Carstens	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
781c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
7823765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt	req->qdio_outb_usage = atomic_read(&adapter->req_q.count);
783c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->issued = get_clock();
784c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_qdio_send(req)) {
785c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		del_timer(&req->timer);
7863765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		spin_lock_irqsave(&adapter->req_list_lock, flags);
7873765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		/* lookup request again, list might have changed */
7883765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		if (zfcp_reqlist_find_safe(adapter, req))
7893765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt			zfcp_reqlist_remove(adapter, req);
7903765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		spin_unlock_irqrestore(&adapter->req_list_lock, flags);
791c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 116, req);
792c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
793c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* Don't increase for unsolicited status */
796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb)
797c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->fsf_req_seq_no++;
798c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
799c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
800c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
801c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
802c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
803c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_status_read - send status read request
804c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
805c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: request flags
806c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, ERROR otherwise
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
808c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_status_read(struct zfcp_adapter *adapter)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
810c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
811c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf;
81244cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
813c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8150406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
816c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
817c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
818c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
819c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
820c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_NO_QTCB,
821c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_status_read);
822025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
823c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
824c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
827c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
828c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
830c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 2;
831c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
832c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
833c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!sr_buf) {
834c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
835c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_buf;
836c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
837c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(sr_buf, 0, sizeof(*sr_buf));
838c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = sr_buf;
839c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_curr(req);
840c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->addr = (void *) sr_buf;
841c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->length = sizeof(*sr_buf);
842059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
844c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval)
845c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_req_send;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
847c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
848c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
849c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_req_send:
850c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_buf:
852c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
853c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
854c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
8550406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
856c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
857c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
858c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
860c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
861c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
862c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
863c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
864c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
865c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
866c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
867c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
869c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
8709467a9b3efdd9041202f71cc270bda827a7ec777Martin Peschke			zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104,
871c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						req);
872c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
876c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
877c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_port_reopen(unit->port, 0, 105, req);
878c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
882c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
885c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 47, req);
886c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
887c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
890c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_boxed(unit, 48, req);
891c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
892c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
895c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (fsq->word[0]) {
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
89765a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
899c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
904c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
910c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_abort_fcp_command - abort running SCSI command
911c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @old_req_id: unsigned long
912c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
913c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
914c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: integer specifying the request flags
915c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: pointer to struct zfcp_fsf_req
916c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
917c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * FIXME(design): should be watched by a timeout !!!
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
920c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
921c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						struct zfcp_adapter *adapter,
922c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						struct zfcp_unit *unit,
923c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						int req_flags)
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
92544cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
926c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
9278a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
9280406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock(&adapter->req_q_lock);
9292450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
930c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
931c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  req_flags, adapter->pool.fsf_req_abort);
933633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	if (IS_ERR(req)) {
934633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig		req = NULL;
935c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
936633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	}
9372abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
938c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
940c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out_error_free;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
942c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
943c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
944c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
946c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
947c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_abort_fcp_command_handler;
948c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
950c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_handle = (u64) old_req_id;
951c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
952c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
953c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
954c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
955c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
956c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout_error_free:
957c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
958c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
959c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
9600406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock(&adapter->req_q_lock);
961c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
964c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
966c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
967c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_ct *send_ct = req->data;
968c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
970c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_ct->status = -EINVAL;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
972c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
977c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_ct_response(req);
978c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_ct->status = 0;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
981c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
987c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
994c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
995c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
997c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
998c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 106, req);
999c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GENERIC_COMMAND_REJECTED:
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
1004c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
1009c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (send_ct->handler)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_ct->handler(send_ct->handler_data);
1011c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1013c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req,
1014c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				struct scatterlist *sg_req,
1015c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				struct scatterlist *sg_resp, int max_sbals)
1016c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
1017c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int bytes;
1018c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1019c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1020c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					sg_req, max_sbals);
1021c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes <= 0)
1022c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -ENOMEM;
1023c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_buf_length = bytes;
1024c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
1025c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1026c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1027c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					sg_resp, max_sbals);
1028c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes <= 0)
1029c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -ENOMEM;
1030c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.resp_buf_length = bytes;
1031c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1032c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1036c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1037c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @ct: pointer to struct zfcp_send_ct with data for request
1038c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
1039c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: if non-null the Generic Service request sent within ERP
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1041c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
1042c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		     struct zfcp_erp_action *erp_action)
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10445ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_wka_port *wka_port = ct->wka_port;
10455ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_adapter *adapter = wka_port->adapter;
1046c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1047c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10490406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1050c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1051c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1053c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
1054c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP, pool);
1055025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1056c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		ret = PTR_ERR(req);
1057c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
10583f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt	}
10593f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt
1060c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp,
1061c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   FSF_MAX_SBALS_PER_REQ);
1062553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (ret)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1065c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_ct_handler;
10665ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->qtcb->header.port_handle = wka_port->handle;
1067c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.service_class = FSF_CLASS_3;
1068c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.timeout = ct->timeout;
1069c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = ct;
1070c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1071c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_san_dbf_event_ct_request(req);
1072c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1073c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (erp_action) {
1074c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = req;
1075c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->erp_action = erp_action;
1076287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt		zfcp_fsf_start_erp_timer(req);
1077c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	} else
1078c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1080c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_req_send(req);
1081c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1082c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1084c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1086c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_send:
1087c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
1088c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (erp_action)
1089c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
1090c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
10910406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1092c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ret;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1095c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1097c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_els *send_els = req->data;
1098c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = send_els->port;
1099c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_els->status = -EINVAL;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1103c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
1108c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_els_response(req);
1109c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_els->status = 0;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
1112c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]){
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
111764b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann			if (port && (send_els->ls_code != ZFCP_LS_ADISC))
111864b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann				zfcp_test_link(port);
1119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/*fall through */
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_RETRY_IF_POSSIBLE:
1122c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ELS_COMMAND_REJECTED:
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1132c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1134c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SBAL_MISMATCH:
1135c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* should never occure, avoided in zfcp_fsf_send_els */
1136c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1138c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
1142aa551daf5cc6fb6c6e09bb993737f9cd46dc7145Heiko Carstens	if (send_els->handler)
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_els->handler(send_els->handler_data);
1144c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1146c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1148c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @els: pointer to struct zfcp_send_els with data for the command
1149c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig */
1150c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_els(struct zfcp_send_els *els)
1151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
1152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = els->adapter;
1154c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
1155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
1156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&els->port->status) &
1158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
1159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
1160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
11610406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock(&adapter->req_q_lock);
11622450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
1165c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP, NULL);
1166025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		ret = PTR_ERR(req);
1168c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1169c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1170c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
117144cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2);
117244cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig
1173c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
1175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
1177c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_els_handler;
1178c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->d_id = els->d_id;
1179c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->service_class = FSF_CLASS_3;
1180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->timeout = 2 * R_A_TOV;
1181c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = els;
1182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1183c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_san_dbf_event_els_request(req);
1184c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1185c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1186c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_req_send(req);
1187c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1188c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
1189c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
1191c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1192c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_send:
1193c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
1194c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
11950406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock(&adapter->req_q_lock);
1196c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ret;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1199c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
120144cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
120352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1204c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
12060406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
12072450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1208c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1209c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1210c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_EXCHANGE_CONFIG_DATA,
1211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1213025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1218c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
121952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
122052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1222c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.config.feature_selection =
1223aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_CFDC |
1224aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_LUN_SHARING |
12259eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin			FSF_FEATURE_NOTIFICATION_LOST |
1226aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_UPDATE_ALERT;
1227c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1228c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_config_data_handler;
1229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1232c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1237c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
12380406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
123952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
124052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1242c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
1243c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				       struct fsf_qtcb_bottom_config *data)
124452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
124544cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1246c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
1247c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1248c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
12490406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1250c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1251c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1252c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
1254c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  0, NULL);
1255025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
125852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
125952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
126152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
126252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_config_data_handler;
126452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1265c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.config.feature_selection =
126652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_CFDC |
126752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_LUN_SHARING |
126852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_NOTIFICATION_LOST |
126952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_UPDATE_ALERT;
127052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
127152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
1272c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->data = data;
127352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1274c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
12770406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1278553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!retval)
1279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
1280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
128152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1282c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
128352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data - request information about local port
1289aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin * @erp_action: ERP action for the adapter for which port data is requested
1290c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1292c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
129444cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1295c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
129652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1297c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1299553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
130052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13020406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
13032450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1305c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
1306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1308025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1311aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
1312aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
131452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
131552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_port_data_handler;
1318c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1319c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
132052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1321287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1322c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
132552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		erp_action->fsf_req = NULL;
132652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
1327c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
13280406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
132952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
133052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
133152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
133252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig/**
133352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig * zfcp_fsf_exchange_port_data_sync - request information about local port
1334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
1335c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @data: pointer to struct fsf_qtcb_bottom_port
1336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
133752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig */
1338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
1339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				     struct fsf_qtcb_bottom_port *data)
134052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
134144cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
1343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
134452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1345553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
134652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
134752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
13480406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
13492450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1351c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1352c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
1353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  NULL);
1354025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1356c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
135952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
1360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->data = data;
136152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1362c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
136352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
136452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
136552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1366c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_port_data_handler;
1367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1368c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
13700406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1371553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!retval)
1372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
1373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
1374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1379c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1381c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1382c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_plogi *plogi;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
138644cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_ALREADY_OPEN:
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1395c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
1396ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "Not enough FCP adapter resources to open "
13977ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 "remote port 0x%016Lx\n",
13987ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 (unsigned long long)port->wwpn);
1399c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_failed(port, 31, req);
1400c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1406c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
1409c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_warn(&req->adapter->ccw_device->dev,
1410ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "Remote port 0x%016Lx could not be opened\n",
14117ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				 (unsigned long long)port->wwpn);
1412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_port_failed(port, 32, req);
1413c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
1421d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1422d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
1423d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1439c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
1440c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
1441c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			if (plogi->serv_param.wwpn != port->wwpn)
1442c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID,
1443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						  &port->status);
1444c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			else {
1445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				port->wwnn = plogi->serv_param.wwnn;
1446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_fc_plogi_evaluate(port, plogi);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
1451c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1457c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_port - create and send open port request
1458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1461c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
146344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1464c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1467c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
14680406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1469c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1470c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1471c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_OPEN_PORT_WITH_DID,
1474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1476025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_port_handler;
1486c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.d_id = erp_action->port->d_id;
1487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1491287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1492c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1494c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1497c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
14980406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1502c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
150744cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1509c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, 107, req);
1512c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
1517c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_port_status(port, 33, req,
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1524c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1525c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_port - create and send close port request
1526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1527c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1529c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
153144cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1532c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1533c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1534c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1535c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
15360406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1539c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
1541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1542c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1543025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1546c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1548c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1552c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_port_handler;
1553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1554c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1555c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1556c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1557c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1558287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1559c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1561c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1564c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
15650406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15695ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligstatic void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
15705ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
15715ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_wka_port *wka_port = req->data;
15725ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
15735ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
15745ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
15755ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
15765ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
15775ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
15785ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
15795ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	switch (header->fsf_status) {
15805ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
15815ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		dev_warn(&req->adapter->ccw_device->dev,
15825ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig			 "Opening WKA port 0x%x failed\n", wka_port->d_id);
15835ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
15845ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15855ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_ACCESS_DENIED:
15865ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
15875ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		break;
15885ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_PORT_ALREADY_OPEN:
15891c1cba17a9078c83a80a099bc207b208d664a13aChristof Schmitt		break;
15905ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_GOOD:
15915ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->handle = header->port_handle;
15925ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->status = ZFCP_WKA_PORT_ONLINE;
15935ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
15945ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligout:
15955ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	wake_up(&wka_port->completion_wq);
15965ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
15975ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
15985ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig/**
15995ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * zfcp_fsf_open_wka_port - create and send open wka-port request
16005ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * @wka_port: pointer to struct zfcp_wka_port
16015ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * Returns: 0 on success, error otherwise
16025ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig */
16035ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligint zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
16045ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
16055ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct qdio_buffer_element *sbale;
16065ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_adapter *adapter = wka_port->adapter;
16075ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_fsf_req *req;
16085ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	int retval = -EIO;
16095ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16100406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
16115ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
16125ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16135ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16145ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req = zfcp_fsf_req_create(adapter,
16155ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  FSF_QTCB_OPEN_PORT_WITH_DID,
16165ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
16175ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  adapter->pool.fsf_req_erp);
16185ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (unlikely(IS_ERR(req))) {
16195ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		retval = PTR_ERR(req);
16205ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16215ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
16225ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16235ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale = zfcp_qdio_sbale_req(req);
16245ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
16255ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
16265ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16275ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->handler = zfcp_fsf_open_wka_port_handler;
16285ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->qtcb->bottom.support.d_id = wka_port->d_id;
16295ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->data = wka_port;
16305ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16315ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
16325ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	retval = zfcp_fsf_req_send(req);
16335ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (retval)
16345ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		zfcp_fsf_req_free(req);
16355ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligout:
16360406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
16375ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	return retval;
16385ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
16395ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16405ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligstatic void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
16415ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
16425ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_wka_port *wka_port = req->data;
16435ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16445ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
16455ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
164641bfcf90101601f9507240ff0435c1b73d28a132Swen Schillig		zfcp_erp_adapter_reopen(wka_port->adapter, 0, 84, req);
16475ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
16485ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16495ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	wka_port->status = ZFCP_WKA_PORT_OFFLINE;
16505ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	wake_up(&wka_port->completion_wq);
16515ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
16525ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16535ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig/**
16545ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * zfcp_fsf_close_wka_port - create and send close wka port request
16555ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * @erp_action: pointer to struct zfcp_erp_action
16565ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * Returns: 0 on success, error otherwise
16575ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig */
16585ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligint zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
16595ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
16605ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct qdio_buffer_element *sbale;
16615ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_adapter *adapter = wka_port->adapter;
16625ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_fsf_req *req;
16635ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	int retval = -EIO;
16645ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16650406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
16665ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
16675ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16685ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16695ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
16705ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
16715ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  adapter->pool.fsf_req_erp);
16725ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (unlikely(IS_ERR(req))) {
16735ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		retval = PTR_ERR(req);
16745ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16755ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
16765ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16775ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale = zfcp_qdio_sbale_req(req);
16785ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
16795ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
16805ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16815ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->handler = zfcp_fsf_close_wka_port_handler;
16825ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->data = wka_port;
16835ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->qtcb->header.port_handle = wka_port->handle;
16845ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16855ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
16865ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	retval = zfcp_fsf_req_send(req);
16875ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (retval)
16885ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		zfcp_fsf_req_free(req);
16895ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligout:
16900406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
16915ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	return retval;
16925ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
16935ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
1694c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1696c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1697c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1700c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1705c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, 108, req);
1706c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1709c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1712c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(port, 50, req);
1713c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
17155c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		/* can't use generic zfcp_erp_modify_port_status because
17165c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
17175c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
17185c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		list_for_each_entry(unit, &port->unit_list_head, list)
17195c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
17205c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt					  &unit->status);
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1725c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1727c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
1737c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					  &unit->status);
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1741c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1745c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1746c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_physical_port - close physical port
1747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1748c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1750c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
175244cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1753c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1754c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1755c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1756c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
17570406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1758c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT,
1762c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1763c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1764025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1765c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1766c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1767c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1769c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
1770c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1771c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1773c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1774c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1776c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_physical_port_handler;
1777c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1778c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
1779c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&erp_action->port->status);
1780c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1781287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1782c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1784c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1787c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
17880406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1792c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
1795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
1796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
1797c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
1798c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_queue_designator *queue_designator =
1799c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&header->fsf_status_qual.fsf_queue_designator;
1800aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	int exclusive, readwrite;
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1802c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
180344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1806b64ddf96456cde17be22bf74cafed381a29d58baHeiko Carstens			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1814c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req);
1815c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1819c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
1821553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1824c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 51, req);
1825c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1826c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
1829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0])
1830553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			dev_warn(&adapter->ccw_device->dev,
1831ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "LUN 0x%Lx on port 0x%Lx is already in "
1832ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "use by CSS%d, MIF Image ID %x\n",
18337ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				 (unsigned long long)unit->fcp_lun,
18347ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				 (unsigned long long)unit->port->wwpn,
1835ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->cssid,
1836ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->hla);
1837c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else
1838553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			zfcp_act_eval_err(adapter,
1839553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					  header->fsf_status_qual.word[2]);
1840c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_access_denied(unit, 60, req);
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
1843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
1846c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&adapter->ccw_device->dev,
1847ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "No handle is available for LUN "
1848ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "0x%016Lx on port 0x%016Lx\n",
18497ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 (unsigned long long)unit->fcp_lun,
18507ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 (unsigned long long)unit->port->wwpn);
1851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_failed(unit, 34, req);
1852c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
1853c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_INVALID_COMMAND_OPTION:
1854c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
185965a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1860c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1862c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
1870aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1871aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
1872aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
1873aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
1874aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			exclusive = (bottom->lun_access_info &
1875aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_EXCLUSIVE);
1876aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			readwrite = (bottom->lun_access_info &
1877aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
1878aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
1886c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_info(&adapter->ccw_device->dev,
1887ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "SCSI device at LUN 0x%016Lx on port "
1888ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "0x%016Lx opened read-only\n",
18897ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					 (unsigned long long)unit->fcp_lun,
18907ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					 (unsigned long long)unit->port->wwpn);
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
1894c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1895ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Exclusive read-only access not "
1896ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, "
1897ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"port 0x%016Lx)\n",
18987ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->fcp_lun,
18997ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->port->wwpn);
1900c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_failed(unit, 35, req);
1901c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1902c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, 80, req);
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
1904c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1905ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Shared read-write access not "
1906ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, port "
1907ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"0x%016Lx\n)",
19087ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->fcp_lun,
19097ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->port->wwpn);
1910c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_failed(unit, 36, req);
1911c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1912c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, 81, req);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1919c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1920c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_unit - open unit
1921c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1922c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1924c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
192644cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1927c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1928c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1929c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1930c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
19310406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1935c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN,
1936c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1937c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1938025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1940c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1941c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1942c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1943c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1947c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1948c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
1949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_unit_handler;
1950c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
1951c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1952c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1953c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1954c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
1955c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
1956c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1957287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1958c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1960c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1963c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
19640406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1968c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1970c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1972c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
197344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1975c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1977c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req);
1978c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
1981c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, 111, req);
1982c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1985c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 52, req);
1986c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1987c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
1990c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (req->qtcb->header.fsf_status_qual.word[0]) {
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
199265a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1993c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1995c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2006c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_unit - close zfcp unit
2007c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_unit
2008c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2010c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
201244cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2013c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
2014c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
2015c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20170406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
2018c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2020c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
2021c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
2022c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
2023025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2024c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
2025c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2026c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2028c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2029c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2032c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
2033c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = erp_action->unit->handle;
2034c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_unit_handler;
2035c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
2036c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
2037c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
2038fdf234527a070f6fc89f3ec5ee4ae1b263e59939Christof Schmitt
2039287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
2040c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2041c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval) {
2042c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
2043c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
2044c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2045c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
20460406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
2047c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2050c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmittstatic void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
2051c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
2052c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat_rec->sum += lat;
2053c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->min = min(lat_rec->min, lat);
2054c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->max = max(lat_rec->max, lat);
2055c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt}
2056c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2057c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
2058c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
2059c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct fsf_qual_latency_info *lat_inf;
2060c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct latency_cont *lat;
2061c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->unit;
2062c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	unsigned long flags;
2063c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2064c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
2065c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2066c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->bottom.io.data_direction) {
2067c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_READ:
2068c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.read;
2069c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
2070c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_WRITE:
2071c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.write;
2072c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
2073c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_CMND:
2074c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.cmd;
2075c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
2076c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	default:
2077c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		return;
2078c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	}
2079c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2080c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	spin_lock_irqsave(&unit->latencies.lock, flags);
2081c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
2082c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
2083c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat->counter++;
2084c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock_irqrestore(&unit->latencies.lock, flags);
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20870997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#ifdef CONFIG_BLK_DEV_IO_TRACE
20880997f1c5fec0b540784611036d458a84a1f7029aStefan Rasplstatic void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
20890997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl{
20900997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct fsf_qual_latency_info *lat_inf;
20910997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
20920997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct request *req = scsi_cmnd->request;
20930997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct zfcp_blk_drv_data trace;
20940997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	int ticks = fsf_req->adapter->timer_ticks;
20950997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
20960997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.flags = 0;
20970997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.magic = ZFCP_BLK_DRV_DATA_MAGIC;
20980997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
20990997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.flags |= ZFCP_BLK_LAT_VALID;
21000997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
21010997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.channel_lat = lat_inf->channel_lat * ticks;
21020997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.fabric_lat = lat_inf->fabric_lat * ticks;
21030997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	}
21040997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
21050997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.flags |= ZFCP_BLK_REQ_ERROR;
21060997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.inb_usage = fsf_req->qdio_inb_usage;
21070997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.outb_usage = fsf_req->qdio_outb_usage;
21080997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
21090997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	blk_add_driver_data(req->q, req, &trace, sizeof(trace));
21100997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl}
21110997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#else
21120997f1c5fec0b540784611036d458a84a1f7029aStefan Rasplstatic inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
21130997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl{
21140997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl}
21150997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#endif
21160997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
2117c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct scsi_cmnd *scpnt = req->data;
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
2121c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
2123f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2126553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (unlikely(!scpnt))
2127c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
2128553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
2129c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&req->adapter->abort_lock, flags);
2130c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2131c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
2132feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_SOFT_ERROR);
2133feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_driver_byte(scpnt, SUGGEST_RETRY);
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2137c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
2138feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_ERROR);
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2142feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann	set_msg_byte(scpnt, COMMAND_COMPLETE);
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2146c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
2147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_latency(req);
2148c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
21490997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	zfcp_fsf_trace_latency(req);
21500997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
2152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fcp_rsp_info[3] == RSP_CODE_GOOD)
2153feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_OK);
2154c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2155feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
21566f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
2161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
2162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			  fcp_rsp_iu->fcp_rsp_len;
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21669d058ecfd444d247b7448e0ef44647514d91a4f2FUJITA Tomonori		memcpy(scpnt->sense_buffer,
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
21717936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
21727936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
21737936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		    scpnt->underflow)
2174feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
21778a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
2178c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req);
21798a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
2180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req);
21818a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
2182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req);
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2192c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&req->adapter->abort_lock, flags);
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
2198c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
2199f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
2202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	     (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2203c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
2204c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2206c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2207c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
2208c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2209c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit;
2210c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
2211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
2213c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->data;
2214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->unit;
2216c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2217c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2220c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (header->fsf_status) {
2221c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_HANDLE_MISMATCH:
2222c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
2223c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req);
2224c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2225c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2226c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_FCPLUN_NOT_VALID:
2227c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_HANDLE_NOT_VALID:
2228c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, 113, req);
2229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2231c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2232c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ACCESS_DENIED:
2235c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
2236c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2237c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_DIRECTION_INDICATOR_NOT_VALID:
2238c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2239ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect direction %d, unit 0x%016Lx on port "
2240ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%016Lx closed\n",
2241c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.data_direction,
22427ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->fcp_lun,
22437ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->port->wwpn);
2244c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req);
2245c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2246c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2247c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_CMND_LENGTH_NOT_VALID:
2248c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2249ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect CDB length %d, unit 0x%016Lx on "
2250ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"port 0x%016Lx closed\n",
2251c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.fcp_cmnd_length,
22527ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->fcp_lun,
22537ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->port->wwpn);
2254c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req);
2255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_BOXED:
2258c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 53, req);
2259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2262c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_BOXED:
2263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_boxed(unit, 54, req);
2264c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2265c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2266c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
2268c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0] ==
2269c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
2270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_test_link(unit->port);
2271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2274c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
2275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
2276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_ctm_handler(req);
2277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else {
2278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_command_task_handler(req);
2279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->unit = NULL;
2280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_unit_put(unit);
2281c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22847ba58c9cc16d296290fe645acb11db2b01276544Swen Schilligstatic void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
22857ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig{
22867ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	u32 *fcp_dl_ptr;
22877ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig
22887ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	/*
22897ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 * fcp_dl_addr = start address of fcp_cmnd structure +
22907ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 * size of fixed part + size of dynamically sized add_dcp_cdb field
22917ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 * SEE FCP-2 documentation
22927ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 */
22937ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
22947ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(fcp_cmd->add_fcp_cdb_length << 2));
22957ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	*fcp_dl_ptr = fcp_dl;
22967ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig}
22977ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig
2298c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
2300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: adapter where scsi command is issued
2301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: unit where command is sent to
2302c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @scsi_cmnd: scsi command to be sent
2303c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @timer: timer to be started when request is initiated
2304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: flags for fsf_request
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
2307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   struct zfcp_unit *unit,
2308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   struct scsi_cmnd *scsi_cmnd,
2309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   int use_timer, int req_flags)
23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2311c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
2312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
2313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned int sbtype;
2314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int real_bytes, retval = -EIO;
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2318c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23200406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock(&adapter->req_q_lock);
23212450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
2322c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2323c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2325025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2326c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
2327c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2328c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_get(unit);
2331c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->unit = unit;
2332c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = scsi_cmnd;
2333c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2335c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2337c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
2341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
2343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * set depending on data direction:
2344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in SBALE (SB Type)
2345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in QTCB
2346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in FCP_CMND IU
2347c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
2348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (scsi_cmnd->sc_data_direction) {
2349c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_NONE:
2350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2351c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_FROM_DEVICE:
2354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
2356c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->rddata = 1;
2357c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_TO_DEVICE:
2359c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_WRITE;
2361c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->wddata = 1;
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_BIDIRECTIONAL:
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EIO;
2366c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely((scsi_cmnd->device->simple_tags) ||
2370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		   ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
2371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
2372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
2373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = UNTAGGED;
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2376c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
2377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->add_fcp_cdb_length =
2378c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2380c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
238145633fdc9615f9fd2a0ae18e301562298b15abf3Christof Schmitt
2382c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
23837ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
2386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     scsi_sglist(scsi_cmnd),
2387c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     FSF_MAX_SBALS_PER_REQ);
2388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(real_bytes < 0)) {
2389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
2390c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EIO;
2391c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
2393ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"Oversize data package, unit 0x%016Lx "
2394ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"on port 0x%016Lx closed\n",
23957ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				(unsigned long long)unit->fcp_lun,
23967ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				(unsigned long long)unit->port->wwpn);
2397c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_unit_shutdown(unit, 0, 131, req);
2398c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EINVAL;
2399c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
2400c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2403c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2405c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (use_timer)
2406c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2409c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(retval))
2410c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_scsi_cmnd:
2415c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_put(unit);
2416c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2417c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = NULL;
2418c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
24190406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock(&adapter->req_q_lock);
2420c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2424c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_ctm - send SCSI task management command
2425c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp-adapter
2426c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
2427c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @tm_flags: unsigned byte for task management flags
2428c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: int request flags
2429c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct fsf_req, NULL otherwise
24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2431c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
2432c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_unit *unit,
2433c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   u8 tm_flags, int req_flags)
24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
243544cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2436c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2437c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2439c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2440c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2441c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24430406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock(&adapter->req_q_lock);
24442450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
2445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2448633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	if (IS_ERR(req)) {
2449633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig		req = NULL;
2450c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2451633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	}
24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2453c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2454c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
2455c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2457c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = 	sizeof(struct fcp_cmnd_iu) +
24617ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig						sizeof(u32);
2462c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2463c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2464c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2467c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
2468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2469c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->task_management_flags = tm_flags;
24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
2473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
2477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
24780406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock(&adapter->req_q_lock);
2479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
2480c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
2483c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2484c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb->header.fsf_status != FSF_GOOD)
2485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_control_file - control file upload/download
2490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
2491c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc
2492c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2494c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_fsf_cfdc *fsf_cfdc)
24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
249744cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
2500c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int direction, retval = -EIO, bytes;
2501c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2502c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
2503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EOPNOTSUPP);
2504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2505c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (fsf_cfdc->command) {
2506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
2507c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_WRITE;
2508c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2509c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_UPLOAD_CONTROL_FILE:
2510c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_READ;
2511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2512c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
2513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EINVAL);
2514c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25160406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
2517c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
2518c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2520c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL);
2521025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2522c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EPERM;
2523c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2524c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_control_file_handler;
25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2528c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2529c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= direction;
25308a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2531c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
2532c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
2533c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->option = fsf_cfdc->option;
25348a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2535c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
2536c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					FSF_MAX_SBALS_PER_REQ);
2537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes != ZFCP_CFDC_MAX_SIZE) {
2538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
2539c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
2540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2545c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
25460406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
25478a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2548c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!retval) {
2549c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
2550c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
2551c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return req;
25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ERR_PTR(retval);
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2555