zfcp_fsf.c revision 44cc76f2d154aa24340354b4711a0fe7f8f08adc
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
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "zfcp_ext.h"
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_request_timeout_handler(unsigned long data)
12287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
13287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
14287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62,
15287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt				NULL);
16287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
17287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
18287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
19287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt				 unsigned long timeout)
20287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
21287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
22287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.data = (unsigned long) fsf_req->adapter;
23287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.expires = jiffies + timeout;
24287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	add_timer(&fsf_req->timer);
25287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
26287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
27287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req)
28287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
29287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	BUG_ON(!fsf_req->erp_action);
30287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.function = zfcp_erp_timeout_handler;
31287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
32287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.expires = jiffies + 30 * HZ;
33287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	add_timer(&fsf_req->timer);
34287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
35287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* association between FSF command and FSF QTCB type */
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 fsf_qtcb_type[] = {
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND,
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND,
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND,
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND,
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND,
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
54553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
55c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	u16 subtable = table >> 16;
56553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	u16 rule = table & 0xffff;
57ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
58553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
59ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	if (subtable && subtable < ARRAY_SIZE(act_type))
60553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		dev_warn(&adapter->ccw_device->dev,
61ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "Access denied according to ACT rule type %s, "
62ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "rule %d\n", act_type[subtable], rule);
63553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
64553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
65553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
66553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					struct zfcp_port *port)
67553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
68553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct fsf_qtcb_header *header = &req->qtcb->header;
69553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	dev_warn(&req->adapter->ccw_device->dev,
70ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		 "Access denied to port 0x%016Lx\n",
71553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		 port->wwpn);
72553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
73553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
74553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_erp_port_access_denied(port, 55, req);
75553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
76553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
77553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
78553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
79553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					struct zfcp_unit *unit)
80553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
81553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct fsf_qtcb_header *header = &req->qtcb->header;
82553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	dev_warn(&req->adapter->ccw_device->dev,
83ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		 "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
84553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		 unit->fcp_lun, unit->port->wwpn);
85553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
86553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
87553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_erp_unit_access_denied(unit, 59, req);
88553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
89553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
90553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
91553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
92553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
93ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	dev_err(&req->adapter->ccw_device->dev, "FCP device not "
94ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		"operational because of an unsupported FC class\n");
95553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req);
96553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
97553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
98553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
99c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
100c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_free - free memory used by fsf request
101c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_req: pointer to struct zfcp_fsf_req
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
103c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligvoid zfcp_fsf_req_free(struct zfcp_fsf_req *req)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
105c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->pool)) {
106c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		mempool_free(req, req->pool);
107dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
108dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
109dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens
110c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb) {
111c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req);
112dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
113dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
116c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
117c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
118c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
120869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Never ever call this without shutting down the adapter first.
121869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Otherwise the adapter would continue using and corrupting s390 storage.
122869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Included BUG_ON() call to ensure this is done.
123869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * ERP is supposed to be the only user of this function.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1256fcc47111ae14f284007e1b9a5002babb01d913cSwen Schilligvoid zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
127c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req, *tmp;
128fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	unsigned long flags;
1296fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig	LIST_HEAD(remove_queue);
130869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	unsigned int i;
131fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
132c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
133fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_lock_irqsave(&adapter->req_list_lock, flags);
134869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	for (i = 0; i < REQUEST_LIST_SIZE; i++)
1356fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig		list_splice_init(&adapter->req_list[i], &remove_queue);
136fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
137fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
138c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_for_each_entry_safe(req, tmp, &remove_queue, list) {
139c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		list_del(&req->list);
140c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
141c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_complete(req);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
148c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
149c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port;
150c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int d_id = sr_buf->d_id & ZFCP_DID_MASK;
151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned long flags;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&zfcp_data.config_lock, flags);
154c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_for_each_entry(port, &adapter->port_list_head, list)
155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (port->d_id == d_id) {
156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			read_unlock_irqrestore(&zfcp_data.config_lock, flags);
157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			switch (sr_buf->status_subtype) {
158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_port_reopen(port, 0, 101, req);
160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				break;
161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			case FSF_STATUS_READ_SUB_ERROR_PORT:
162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_port_shutdown(port, 0, 122, req);
163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				break;
164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			}
165c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
170c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
171c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					 struct fsf_link_down_info *link_down)
172aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin{
173c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
174698ec01635819c5ae60090bb4efcbeffc41642fbMartin Peschke
175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
176ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin		return;
177ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
178ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin	atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
179ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!link_down)
1812f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		goto out;
182ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
183aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (link_down->error_code) {
184aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_LIGHT:
185c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
186ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "There is no light signal from the local "
187ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "fibre channel cable\n");
188aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
189aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WRAP_PLUG:
190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
191ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "There is a wrap plug instead of a fibre "
192ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "channel cable\n");
193aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
194aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP:
195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
196ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The adjacent fibre channel node does not "
197ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "support FCP\n");
198aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
199aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FIRMWARE_UPDATE:
200c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
201ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP device is suspended because of a "
202ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "firmware update\n");
203553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		break;
204aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_INVALID_WWPN:
205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
206ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP device detected a WWPN that is "
207ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "duplicate or not valid\n");
208aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
209aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
210c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
211ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The fibre channel fabric does not support NPIV\n");
212aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
213aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP_RESOURCES:
214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
215ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP adapter cannot support more NPIV ports\n");
216aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
217aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
218c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
219ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The adjacent switch cannot support "
220ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "more NPIV ports\n");
221aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
222aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
223c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
224ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP adapter could not log in to the "
225ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "fibre channel fabric\n");
226aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
227aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
228c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
229ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The WWPN assignment file on the FCP adapter "
230ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been damaged\n");
231aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
232aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
233c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
234ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The mode table on the FCP adapter "
235ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been damaged\n");
236aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
237aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
238c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
239ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "All NPIV ports on the FCP adapter have "
240ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "been assigned\n");
241aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
242aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	default:
243c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
244ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The link between the FCP adapter and "
245ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "the FC fabric is down\n");
246aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
247c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
248c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_erp_adapter_failed(adapter, id, req);
249aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin}
250aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
251c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
254c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_link_down_info *ldi =
255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		(struct fsf_link_down_info *) &sr_buf->payload;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (sr_buf->status_subtype) {
258c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 38, ldi);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_FDISC_FAILED:
262c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 39, ldi);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
264c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
265c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 40, NULL);
266c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	};
267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
272c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
274c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf);
276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		mempool_free(sr_buf, adapter->pool.data_status_read);
277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
283c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (sr_buf->status_type) {
284c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_PORT_CLOSED:
285c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_port_closed(req);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
287c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_INCOMING_ELS:
288c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fc_incoming_els(req);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
290c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
292c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
293ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		dev_warn(&adapter->ccw_device->dev,
294ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The error threshold for checksum statistics "
295ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been exceeded\n");
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
297c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_LINK_DOWN:
298c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_link_down(req);
299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_LINK_UP:
301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_info(&adapter->ccw_device->dev,
302ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The local link has been restored\n");
303c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* All ports should be marked as ready to run again */
304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_adapter_status(adapter, 30, NULL,
305c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_STATUS_COMMON_RUNNING,
306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_SET);
307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter,
308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_COMMON_ERP_FAILED,
310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					102, req);
311c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_NOTIFICATION_LOST:
313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_adapter_access_changed(adapter, 135, req);
315c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			schedule_work(&adapter->scan_work);
317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
318c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_CFDC_UPDATED:
319c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_access_changed(adapter, 136, req);
320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
321c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
322c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->adapter_features = sr_buf->payload.word[0];
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
326c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
327c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_inc(&adapter->stat_miss);
330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	schedule_work(&adapter->stat_work);
331c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
333c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
335c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status_qual.word[0]) {
336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_FCP_RSP_AVAILABLE:
337c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_NO_RETRY_POSSIBLE:
339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_COMMAND_ABORTED:
342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_NO_RECOM:
345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
346ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter reported a problem "
347ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"that cannot be recovered\n");
348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req);
349c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
351c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* all non-return stats set FSFREQ_ERROR*/
352c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
357c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
361c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_UNKNOWN_COMMAND:
362c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
363ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter does not recognize the command 0x%x\n",
364c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->header.fsf_command);
365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req);
366c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
368c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_fsfstatus_qual_eval(req);
370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
376c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
378c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
380c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_response(req);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
382c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
383c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
384c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->prefix.prot_status) {
389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_GOOD:
390c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_FSF_STATUS_PRESENTED:
391c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_QTCB_VERSION_ERROR:
393c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
394ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"QTCB version 0x%x not supported by FCP adapter "
395ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
396ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			psq->word[0], psq->word[1]);
397c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 117, req);
398c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
399c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_ERROR_STATE:
400c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_SEQ_NUMB_ERROR:
401c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 98, req);
402c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_RETRY;
403c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
404c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_UNSUPP_QTCB_TYPE:
405c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
406ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The QTCB type is not supported by the FCP adapter\n");
407c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 118, req);
408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
409c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_HOST_CONNECTION_INITIALIZING:
410c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
411c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
413c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_DUPLICATE_REQUEST_ID:
414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
415ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%Lx is an ambiguous request identifier\n",
416c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(unsigned long long)qtcb->bottom.support.req_handle);
417c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 78, req);
418c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
419c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_LINK_DOWN:
420c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info);
421c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* FIXME: reopening adapter now? better wait for link up */
422c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 79, req);
423c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
424c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_REEST_QUEUE:
425c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* All ports should be marked as ready to run again */
426c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_adapter_status(adapter, 28, NULL,
427c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_STATUS_COMMON_RUNNING,
428c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_SET);
429c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter,
430c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
431c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_COMMON_ERP_FAILED, 99, req);
432c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
433c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
434c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
435ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%x is not a valid transfer protocol status\n",
436c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			qtcb->prefix.prot_status);
437c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 119, req);
438c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
439c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
442c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_complete - process completion of a FSF request
444c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_req: The FSF request that has been completed.
445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * When a request has been completed either from the FCP adapter,
447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * or it has been dismissed due to a queue shutdown, this function
448c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * is called to process the completion status and trigger further
449c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * events related to the FSF request.
450c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig */
451c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligvoid zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
453c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
454c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_handler(req);
455c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	del_timer(&req->timer);
459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_protstatus_eval(req);
460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_fsfstatus_eval(req);
461c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler(req);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
463c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->erp_action)
464287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt		zfcp_erp_notify(req->erp_action, 0);
465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
467c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
469c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
470c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* notify initiator waiting for the requests completion */
471c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * FIXME: Race! We must not access fsf_req here as it might have been
473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * flag. It's an improbable case. But, we have the same paranoia for
475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * the cleanup flag already.
476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * Might better be handled using complete()?
477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * (setting the flag and doing wakeup ought to be atomic
478c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *  with regard to checking the flag as long as waitqueue is
479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *  part of the to be released structure)
480c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wake_up(&req->completion_wq);
482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
484c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
486c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_config *bottom;
487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.config;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
492c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->data)
493c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(req->data, bottom, sizeof(*bottom));
494c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
496c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
497c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_speed(shost) = bottom->fc_link_speed;
499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
500c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
501c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->hydra_version = bottom->adapter_type;
502c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->timer_ticks = bottom->timer_interval;
503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (fc_host_permanent_port_name(shost) == -1)
505c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
507c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (bottom->fc_topology) {
508c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_P2P:
509c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
510c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
512c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_PTP;
513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
514c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_FABRIC:
515c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
516c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
517c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_AL:
518c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
519c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
520c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
521ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Unknown or unsupported arbitrated loop "
522ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"fibre channel topology detected\n");
523ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
524c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
530c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
531553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
532553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct zfcp_adapter *adapter = req->adapter;
533c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
534c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
535c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
536553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->fsf_lic_version = bottom->lic_version;
541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->adapter_features = bottom->adapter_features;
542c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->connection_features = bottom->connection_features;
543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_wwpn = 0;
544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_wwnn = 0;
545c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_d_id = 0;
5468a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
547c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
548c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
549c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (zfcp_fsf_exchange_config_evaluate(req))
550c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
552c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
554ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"FCP adapter maximum QTCB size (%d bytes) "
555ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"is too small\n",
556ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				bottom->max_qtcb_size);
557c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_adapter_shutdown(adapter, 0, 129, req);
558c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
559c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
560c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
561c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
563c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
564c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_node_name(shost) = 0;
565c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_name(shost) = 0;
566c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_id(shost) = 0;
567c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
568c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
569c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->hydra_version = 0;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
572c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
574c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 42,
575c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
577c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
578c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 130, req);
579c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
580c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
582c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
583c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->hardware_version = bottom->hardware_version;
584c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(fc_host_serial_number(shost), bottom->serial_number,
585c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       min(FC_SERIAL_NUMBER_SIZE, 17));
586c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		EBCASC(fc_host_serial_number(shost),
587c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       min(FC_SERIAL_NUMBER_SIZE, 17));
588c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
590c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
591c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
592ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter only supports newer "
593ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"control block versions\n");
594c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 125, req);
595c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
596c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
597c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
598c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
599ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter only supports older "
600ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"control block versions\n");
601c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, 126, req);
602c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
603c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
605c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
606c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
607c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
608c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port;
609c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->data)
612c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(req->data, bottom, sizeof(*bottom));
6139eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin
614c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
615c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = bottom->wwpn;
616c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
617c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
618c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
619c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_supported_speeds(shost) = bottom->supported_speed;
620c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
622c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
623c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
624c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
625c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
626c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
627c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
628c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
629c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
630c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
631c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
632c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
633c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
634c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
635c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 43,
636c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
637aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
639c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
640d26ab06ede83287f99067fee3034c5455a75faf9Swen Schillig
641c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue)
642c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
643d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&queue->lock);
644c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (atomic_read(&queue->count))
645c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 1;
646d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&queue->lock);
647c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6502450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Rasplstatic int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
6512450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl{
6522450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	unsigned int count = atomic_read(&adapter->req_q.count);
6532450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!count)
6542450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
6552450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	return count > 0;
6562450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl}
6572450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl
658c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
659c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
660c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	long ret;
661c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
662c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
663d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&req_q->lock);
664c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = wait_event_interruptible_timeout(adapter->request_wq,
665c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					zfcp_fsf_sbal_check(req_q), 5 * HZ);
666c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret > 0)
667c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 0;
6682450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!ret)
6692450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
670c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
671d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&req_q->lock);
672c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return -EIO;
673c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
674c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
675c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool)
676c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
677c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
678c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = mempool_alloc(pool, GFP_ATOMIC);
679c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!req)
680c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
681c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(req, 0, sizeof(*req));
682c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
683c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
684c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
685c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool)
686c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
687c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req_qtcb *qtcb;
688c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
689c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(pool))
690c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = mempool_alloc(pool, GFP_ATOMIC);
691c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
692c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
693c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					GFP_ATOMIC);
694c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!qtcb))
695c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
696c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
697c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(qtcb, 0, sizeof(*qtcb));
698c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.qtcb = &qtcb->qtcb;
699c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.pool = pool;
700c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
701c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return &qtcb->fsf_req;
702c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
703c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
704c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
705c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						u32 fsf_cmd, int req_flags,
706c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						mempool_t *pool)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
70844cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
710c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
711c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
712951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
713c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req_flags & ZFCP_REQ_NO_QTCB)
714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_noqtcb(pool);
715c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
716c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_qtcb(pool);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
718c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!req))
719c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->req_no == 0)
722c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->req_no++;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
724c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	INIT_LIST_HEAD(&req->list);
725c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_timer(&req->timer);
726c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_waitqueue_head(&req->completion_wq);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
728c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->adapter = adapter;
729c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->fsf_command = fsf_cmd;
730c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->req_id = adapter->req_no++;
731c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_number = 1;
732c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_first = req_q->first;
733c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_last = req_q->first;
734c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 1;
735c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
736c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
737c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].addr = (void *) req->req_id;
738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
739c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
740c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->qtcb)) {
741c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no;
742c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_id = req->req_id;
743c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.ulp_info = 26;
744c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
745c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
746c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.req_handle = req->req_id;
747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.fsf_command = req->fsf_command;
748c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->seq_no = adapter->fsf_req_seq_no;
749c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
750c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].addr = (void *) req->qtcb;
751c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].length = sizeof(struct fsf_qtcb);
752c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
753c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
754c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
755c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
756c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
757c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
758951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
759c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
760c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
762c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
766c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
767c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
768c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
769c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int idx;
770c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
771c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* put allocated FSF request into hash table */
772c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_list_lock);
773c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	idx = zfcp_reqlist_hash(req->req_id);
774c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_add_tail(&req->list, &adapter->req_list[idx]);
775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_list_lock);
776c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
777c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->issued = get_clock();
778c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_qdio_send(req)) {
779c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* Queues are down..... */
780c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		del_timer(&req->timer);
781c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		spin_lock(&adapter->req_list_lock);
782c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_reqlist_remove(adapter, req);
783c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		spin_unlock(&adapter->req_list_lock);
784c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* undo changes in request queue made for this request */
785c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_add(req->sbal_number, &req_q->count);
786c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req_q->first -= req->sbal_number;
787c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req_q->first += QDIO_MAX_BUFFERS_PER_Q;
788c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
789c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 116, req);
790c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
791c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
792c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
793c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* Don't increase for unsolicited status */
794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb)
795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->fsf_req_seq_no++;
796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
797c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
798c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
799c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
800c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
801c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_status_read - send status read request
802c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
803c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: request flags
804c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, ERROR otherwise
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
806c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_status_read(struct zfcp_adapter *adapter)
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
808c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
809c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf;
81044cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
811c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
813d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
814c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
815c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
816c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
817c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
818c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_NO_QTCB,
819c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_status_read);
820025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
821c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
822c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
825c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
826c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
827c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
828c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 2;
829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
830c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
831c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!sr_buf) {
832c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
833c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_buf;
834c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
835c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(sr_buf, 0, sizeof(*sr_buf));
836c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = sr_buf;
837c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_curr(req);
838c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->addr = (void *) sr_buf;
839c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->length = sizeof(*sr_buf);
840059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
841c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
842c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval)
843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_req_send;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
845c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
846c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
847c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_req_send:
848c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
849c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_buf:
850c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
852c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
853d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
854c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
855c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
856c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
857c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
858c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
860c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
861c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
862c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
863c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
864c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
865c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
867c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
8689467a9b3efdd9041202f71cc270bda827a7ec777Martin Peschke			zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104,
869c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						req);
870c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
874c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
875c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_port_reopen(unit->port, 0, 105, req);
876c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
880c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
883c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 47, req);
884c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
885c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
888c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_boxed(unit, 48, req);
889c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
890c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
893c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (fsq->word[0]) {
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
89565a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
897c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
902c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
908c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_abort_fcp_command - abort running SCSI command
909c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @old_req_id: unsigned long
910c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
911c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
912c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: integer specifying the request flags
913c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: pointer to struct zfcp_fsf_req
914c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
915c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * FIXME(design): should be watched by a timeout !!!
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
918c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
919c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						struct zfcp_adapter *adapter,
920c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						struct zfcp_unit *unit,
921c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						int req_flags)
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
92344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
924c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
9258a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
926c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
9272450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
928c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
929c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
930c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  req_flags, adapter->pool.fsf_req_abort);
931025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req))
932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
9332abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
934c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
935c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
936c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out_error_free;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
938c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
940c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
942c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
943c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_abort_fcp_command_handler;
944c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
945c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
946c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_handle = (u64) old_req_id;
947c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
948c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
950c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
951c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
952c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout_error_free:
953c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
954c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
955c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
956c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
957c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
960c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
962c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
963c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_ct *send_ct = req->data;
964c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = send_ct->port;
965c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
967c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_ct->status = -EINVAL;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
969c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
974c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_ct_response(req);
975c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_ct->status = 0;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
978c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_test_link(port);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
985c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
990c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
993c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(port, 49, req);
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{
1044c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = ct->port;
1045c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = port->adapter;
1046c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1047c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1049d4538817287e56abc938900886301a5bdfafbfcdChristof 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;
1066c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = 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:
1091d4538817287e56abc938900886301a5bdfafbfcdChristof 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
1161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	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:
1195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	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
1206d4538817287e56abc938900886301a5bdfafbfcdChristof 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:
1238d4538817287e56abc938900886301a5bdfafbfcdChristof 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
1249d4538817287e56abc938900886301a5bdfafbfcdChristof 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:
1277d4538817287e56abc938900886301a5bdfafbfcdChristof 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
1302d4538817287e56abc938900886301a5bdfafbfcdChristof 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:
1328d4538817287e56abc938900886301a5bdfafbfcdChristof 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
1348d4538817287e56abc938900886301a5bdfafbfcdChristof 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:
1370d4538817287e56abc938900886301a5bdfafbfcdChristof 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 "
1397ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "remote port 0x%016Lx\n", port->wwpn);
1398c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_failed(port, 31, req);
1399c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1405c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
1408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_warn(&req->adapter->ccw_device->dev,
1409ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "Remote port 0x%016Lx could not be opened\n",
1410ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 port->wwpn);
1411c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_port_failed(port, 32, req);
1412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
1420d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1421d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
1422d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1438c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN)
1439c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			break;
1440c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1441c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
1442c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
1443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			if (plogi->serv_param.wwpn != port->wwpn)
1444c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID,
1445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						  &port->status);
1446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			else {
1447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				port->wwnn = plogi->serv_param.wwnn;
1448c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_fc_plogi_evaluate(port, plogi);
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
1453c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_port - create and send open port request
1460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1461c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1463c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
146544cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1467c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1469c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1470d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1471c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_OPEN_PORT_WITH_DID,
1476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1478025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1483c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_port_handler;
1488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.d_id = erp_action->port->d_id;
1489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1491c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1492c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1493287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1494c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1496c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1500d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1508c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
150944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, 107, req);
1514c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
1519c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_port_status(port, 33, req,
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1527c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_port - create and send close port request
1528c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1529c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1531c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
153344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1534c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1535c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1536c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1538d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1539c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1542c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
1543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1545025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1546c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1548c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1550c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1554c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_port_handler;
1555c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1556c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1557c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1558c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1559c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1560287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1561c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1563c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1566c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1567d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1573c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1574c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1577c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1582c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, 108, req);
1583c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1586c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1589c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(port, 50, req);
1590c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1591c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
15925c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		/* can't use generic zfcp_erp_modify_port_status because
15935c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
15945c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
15955c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		list_for_each_entry(unit, &port->unit_list_head, list)
15965c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
15975c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt					  &unit->status);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1602c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1604c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
1614c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1615c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					  &unit->status);
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1618c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1622c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1623c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_physical_port - close physical port
1624c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1625c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1627c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
162944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1630c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1631c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1632c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1633c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1634d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1635c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1638c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT,
1639c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1640c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1641025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1642c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1643c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1644c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1646c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
1647c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1648c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1650c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1651c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1652c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1653c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_physical_port_handler;
1654c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1655c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
1656c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&erp_action->port->status);
1657c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1658287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1659c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1661c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1664c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1665d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1669c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1671c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
1672c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
1673c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
1674c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
1675c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_queue_designator *queue_designator =
1676c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&header->fsf_status_qual.fsf_queue_designator;
1677aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	int exclusive, readwrite;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1679c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
168044cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1683b64ddf96456cde17be22bf74cafed381a29d58baHeiko Carstens			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1691c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req);
1692c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1696c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
1698553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1701c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 51, req);
1702c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1703c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
1706c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0])
1707553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			dev_warn(&adapter->ccw_device->dev,
1708ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "LUN 0x%Lx on port 0x%Lx is already in "
1709ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "use by CSS%d, MIF Image ID %x\n",
1710553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt				 unit->fcp_lun,
1711553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt				 unit->port->wwpn,
1712ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->cssid,
1713ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->hla);
1714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else
1715553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			zfcp_act_eval_err(adapter,
1716553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					  header->fsf_status_qual.word[2]);
1717c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_access_denied(unit, 60, req);
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
1720c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
1723c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&adapter->ccw_device->dev,
1724ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "No handle is available for LUN "
1725ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "0x%016Lx on port 0x%016Lx\n",
1726553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			 unit->fcp_lun, unit->port->wwpn);
1727c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_failed(unit, 34, req);
1728c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
1729c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_INVALID_COMMAND_OPTION:
1730c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
173565a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1736c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
1746aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1747aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
1748aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
1749aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
1750aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			exclusive = (bottom->lun_access_info &
1751aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_EXCLUSIVE);
1752aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			readwrite = (bottom->lun_access_info &
1753aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
1754aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
1762c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_info(&adapter->ccw_device->dev,
1763ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "SCSI device at LUN 0x%016Lx on port "
1764ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "0x%016Lx opened read-only\n",
1765553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					 unit->fcp_lun, unit->port->wwpn);
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
1769c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1770ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Exclusive read-only access not "
1771ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, "
1772ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"port 0x%016Lx)\n",
1773553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					unit->fcp_lun, unit->port->wwpn);
1774c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_failed(unit, 35, req);
1775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1776c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, 80, req);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
1778c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1779ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Shared read-write access not "
1780ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, port "
1781ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"0x%016Lx\n)",
1782553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					unit->fcp_lun, unit->port->wwpn);
1783c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_failed(unit, 36, req);
1784c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1785c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, 81, req);
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1792c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1793c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_unit - open unit
1794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1797c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
179944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1800c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1801c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1802c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1803c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1804d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1805c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1808c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN,
1809c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1810c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1811025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1812c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1813c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1814c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1815c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1816c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1820c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1821c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
1822c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_unit_handler;
1823c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
1824c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1825c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1826c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1827c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
1828c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
1829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1830287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1831c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1833c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1836c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1837d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1845c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
184644cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1848c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1850c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req);
1851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
1854c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, 111, req);
1855c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1858c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 52, req);
1859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1860c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
1863c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (req->qtcb->header.fsf_status_qual.word[0]) {
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
186565a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1866c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1868c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1879c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_unit - close zfcp unit
1880c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_unit
1881c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1883c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
188544cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1886c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1887c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1888c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1890d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1891c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1893c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
1894c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1895c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1896025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1897c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1898c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1899c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
1902c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1905c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1906c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = erp_action->unit->handle;
1907c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_unit_handler;
1908c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
1909c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1910c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1911fdf234527a070f6fc89f3ec5ee4ae1b263e59939Christof Schmitt
1912287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1913c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1914c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval) {
1915c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
1916c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
1917c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1918c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1919d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
1920c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1923c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmittstatic void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
1924c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
1925c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat_rec->sum += lat;
1926c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->min = min(lat_rec->min, lat);
1927c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->max = max(lat_rec->max, lat);
1928c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt}
1929c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1930c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
1931c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
1932c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct fsf_qual_latency_info *lat_inf;
1933c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct latency_cont *lat;
1934c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->unit;
1935c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	unsigned long flags;
1936c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1937c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
1938c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->bottom.io.data_direction) {
1940c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_READ:
1941c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.read;
1942c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
1943c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_WRITE:
1944c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.write;
1945c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
1946c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_CMND:
1947c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.cmd;
1948c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
1949c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	default:
1950c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		return;
1951c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	}
1952c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1953c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	spin_lock_irqsave(&unit->latencies.lock, flags);
1954c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
1955c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
1956c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat->counter++;
1957c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock_irqrestore(&unit->latencies.lock, flags);
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1960c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1962c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct scsi_cmnd *scpnt = req->data;
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
1964c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
1966f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1969553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (unlikely(!scpnt))
1970c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
1971553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
1972c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&req->adapter->abort_lock, flags);
1973c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1974c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
1975feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_SOFT_ERROR);
1976feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_driver_byte(scpnt, SUGGEST_RETRY);
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1980c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
1981feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_ERROR);
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1985feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann	set_msg_byte(scpnt, COMMAND_COMPLETE);
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1989c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
1990c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_latency(req);
1991c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
1993c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fcp_rsp_info[3] == RSP_CODE_GOOD)
1994feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_OK);
1995c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
1996feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
19976f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
2002c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
2003c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			  fcp_rsp_iu->fcp_rsp_len;
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20079d058ecfd444d247b7448e0ef44647514d91a4f2FUJITA Tomonori		memcpy(scpnt->sense_buffer,
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
20127936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
20137936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
20147936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		    scpnt->underflow)
2015feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2017c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
20188a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
2019c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req);
20208a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
2021c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req);
20228a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
2023c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req);
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2033c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&req->adapter->abort_lock, flags);
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2036c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
2039c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
2040f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2042c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
2043c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	     (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2044c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
2045c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2046c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2047c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2048c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
2049c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2050c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit;
2051c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
2052c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2053c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
2054c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->data;
2055c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2056c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->unit;
2057c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2058c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (header->fsf_status) {
2062c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_HANDLE_MISMATCH:
2063c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
2064c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req);
2065c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2066c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2067c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_FCPLUN_NOT_VALID:
2068c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_HANDLE_NOT_VALID:
2069c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, 113, req);
2070c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2072c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2073c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2075c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ACCESS_DENIED:
2076c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
2077c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2078c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_DIRECTION_INDICATOR_NOT_VALID:
2079c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2080ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect direction %d, unit 0x%016Lx on port "
2081ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%016Lx closed\n",
2082c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.data_direction,
2083c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			unit->fcp_lun, unit->port->wwpn);
2084c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req);
2085c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2086c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2087c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_CMND_LENGTH_NOT_VALID:
2088c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2089ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect CDB length %d, unit 0x%016Lx on "
2090ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"port 0x%016Lx closed\n",
2091c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.fcp_cmnd_length,
2092c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			unit->fcp_lun, unit->port->wwpn);
2093c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req);
2094c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2095c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2096c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_BOXED:
2097c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 53, req);
2098c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2099c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2100c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2101c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_BOXED:
2102c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_boxed(unit, 54, req);
2103c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2104c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2105c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2106c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
2107c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0] ==
2108c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
2109c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_test_link(unit->port);
2110c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2113c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
2114c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
2115c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_ctm_handler(req);
2116c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else {
2117c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_command_task_handler(req);
2118c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->unit = NULL;
2119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_unit_put(unit);
2120c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2123c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2124c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
2125c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: adapter where scsi command is issued
2126c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: unit where command is sent to
2127c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @scsi_cmnd: scsi command to be sent
2128c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @timer: timer to be started when request is initiated
2129c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: flags for fsf_request
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2131c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
2132c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   struct zfcp_unit *unit,
2133c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   struct scsi_cmnd *scsi_cmnd,
2134c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   int use_timer, int req_flags)
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2136c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
2137c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
2138c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned int sbtype;
2139c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int real_bytes, retval = -EIO;
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2142c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2143c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2145c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
21462450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
2147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2148c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2149c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2150025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
2152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2154c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_get(unit);
2156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->unit = unit;
2157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = scsi_cmnd;
2158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2165c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
2166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
2168c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * set depending on data direction:
2169c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in SBALE (SB Type)
2170c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in QTCB
2171c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in FCP_CMND IU
2172c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
2173c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (scsi_cmnd->sc_data_direction) {
2174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_NONE:
2175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2178c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_FROM_DEVICE:
2179c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
2181c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->rddata = 1;
2182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2183c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_TO_DEVICE:
2184c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2185c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_WRITE;
2186c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->wddata = 1;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2188c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_BIDIRECTIONAL:
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EIO;
2191c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2194c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely((scsi_cmnd->device->simple_tags) ||
2195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		   ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
2196c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
2197c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
2198c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2199c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = UNTAGGED;
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
2202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->add_fcp_cdb_length =
2203c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
220645633fdc9615f9fd2a0ae18e301562298b15abf3Christof Schmitt
2207c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
2208c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t);
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2210c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
2211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     scsi_sglist(scsi_cmnd),
2212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     FSF_MAX_SBALS_PER_REQ);
2213c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(real_bytes < 0)) {
2214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
2215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EIO;
2216c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2217c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
2218ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"Oversize data package, unit 0x%016Lx "
2219ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"on port 0x%016Lx closed\n",
2220ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				unit->fcp_lun, unit->port->wwpn);
2221c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_unit_shutdown(unit, 0, 131, req);
2222c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EINVAL;
2223c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
2224c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2227c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (use_timer)
2230c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2232c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2233c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(retval))
2234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2236c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2238c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_scsi_cmnd:
2239c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_put(unit);
2240c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2241c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = NULL;
2242c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
2243c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
2244c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2248c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_ctm - send SCSI task management command
2249c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp-adapter
2250c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
2251c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @tm_flags: unsigned byte for task management flags
2252c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: int request flags
2253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct fsf_req, NULL otherwise
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
2256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_unit *unit,
2257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   u8 tm_flags, int req_flags)
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
225944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2264c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2265c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
22682450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
2269c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2272025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req))
2273c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
2277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2281c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2282c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = 	sizeof(struct fcp_cmnd_iu) +
2283c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						sizeof(fcp_dl_t);
2284c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2285c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2286c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2287c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2289c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
2290c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2291c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->task_management_flags = tm_flags;
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2293c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2294c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
2295c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2297c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2298c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
2299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
2300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
2301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
2302c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
2305c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb->header.fsf_status != FSF_GOOD)
2307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2311c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_control_file - control file upload/download
2312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
2313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc
2314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_fsf_cfdc *fsf_cfdc)
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
231944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2321c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
2322c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int direction, retval = -EIO, bytes;
2323c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
2325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EOPNOTSUPP);
2326c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2327c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (fsf_cfdc->command) {
2328c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
2329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_WRITE;
2330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2331c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_UPLOAD_CONTROL_FILE:
2332c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_READ;
2333c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
2335c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EINVAL);
2336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2338d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
2339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
2340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL);
2343025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EPERM;
2345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_control_file_handler;
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2351c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= direction;
23528a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
2354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
2355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->option = fsf_cfdc->option;
23568a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2357c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
2358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					FSF_MAX_SBALS_PER_REQ);
2359c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes != ZFCP_CFDC_MAX_SIZE) {
2360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
2361c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
2362c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2366c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
2368d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
23698a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!retval) {
2371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
2372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
2373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return req;
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ERR_PTR(retval);
23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2377