zfcp_fsf.c revision ff3b24fa5370a7ca618f212284d9b36fcedb9c0e
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 zfcp_adapter *adapter = req->adapter;
625c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
626c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
627c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
628c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
629c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
630c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
631c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
632c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
633c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
634c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
635c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
636c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
637c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
638c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_link_down_info_eval(req, 43,
639c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
640aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
642c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
643d26ab06ede83287f99067fee3034c5455a75faf9Swen Schillig
644c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue)
645c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
646d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&queue->lock);
647c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (atomic_read(&queue->count))
648c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 1;
649d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&queue->lock);
650c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6532450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Rasplstatic int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
6542450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl{
6552450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	unsigned int count = atomic_read(&adapter->req_q.count);
6562450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!count)
6572450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
6582450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	return count > 0;
6592450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl}
6602450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl
661c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
662c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
663c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	long ret;
664c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
665c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
666d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&req_q->lock);
667c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = wait_event_interruptible_timeout(adapter->request_wq,
668c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					zfcp_fsf_sbal_check(req_q), 5 * HZ);
669c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret > 0)
670c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 0;
6712450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!ret)
6722450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
673c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
674d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&req_q->lock);
675c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return -EIO;
676c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
677c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
678c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool)
679c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
680c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
681c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = mempool_alloc(pool, GFP_ATOMIC);
682c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!req)
683c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
684c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(req, 0, sizeof(*req));
685c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
686c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
687c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
688c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool)
689c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
690c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req_qtcb *qtcb;
691c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
692c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(pool))
693c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = mempool_alloc(pool, GFP_ATOMIC);
694c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
695c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
696c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					GFP_ATOMIC);
697c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!qtcb))
698c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
699c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
700c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(qtcb, 0, sizeof(*qtcb));
701c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.qtcb = &qtcb->qtcb;
702c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.pool = pool;
703c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
704c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return &qtcb->fsf_req;
705c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
706c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
707c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
708c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						u32 fsf_cmd, int req_flags,
709c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						mempool_t *pool)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
713c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
715951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
716c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req_flags & ZFCP_REQ_NO_QTCB)
717c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_noqtcb(pool);
718c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
719c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_qtcb(pool);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!req))
722c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
724c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->req_no == 0)
725c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->req_no++;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
727c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	INIT_LIST_HEAD(&req->list);
728c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_timer(&req->timer);
729c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_waitqueue_head(&req->completion_wq);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->adapter = adapter;
732c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->fsf_command = fsf_cmd;
733c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->req_id = adapter->req_no++;
734c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_number = 1;
735c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_first = req_q->first;
736c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_last = req_q->first;
737c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 1;
738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
739c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
740c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].addr = (void *) req->req_id;
741c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
742c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
743c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->qtcb)) {
744c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no;
745c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_id = req->req_id;
746c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.ulp_info = 26;
747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
748c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
749c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.req_handle = req->req_id;
750c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.fsf_command = req->fsf_command;
751c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->seq_no = adapter->fsf_req_seq_no;
752c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
753c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].addr = (void *) req->qtcb;
754c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].length = sizeof(struct fsf_qtcb);
755c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
756c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
757c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
758c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
759c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
760c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
761951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
762c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
763c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
768c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
769c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
770c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
771c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
772c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int idx;
773c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
774c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* put allocated FSF request into hash table */
775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_list_lock);
776c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	idx = zfcp_reqlist_hash(req->req_id);
777c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_add_tail(&req->list, &adapter->req_list[idx]);
778c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_list_lock);
779c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
780c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->issued = get_clock();
781c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_qdio_send(req)) {
782c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* Queues are down..... */
783c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		del_timer(&req->timer);
784c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		spin_lock(&adapter->req_list_lock);
785c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_reqlist_remove(adapter, req);
786c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		spin_unlock(&adapter->req_list_lock);
787c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* undo changes in request queue made for this request */
788c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_add(req->sbal_number, &req_q->count);
789c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req_q->first -= req->sbal_number;
790c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req_q->first += QDIO_MAX_BUFFERS_PER_Q;
791c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
792c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 116, req);
793c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* Don't increase for unsolicited status */
797c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb)
798c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->fsf_req_seq_no++;
799c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
800c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
801c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
802c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
803c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
804c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_status_read - send status read request
805c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
806c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: request flags
807c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, ERROR otherwise
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
809c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_status_read(struct zfcp_adapter *adapter)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
811c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
812c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf;
813c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	volatile struct qdio_buffer_element *sbale;
814c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
816d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
817c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
818c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
819c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
820c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
821c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_NO_QTCB,
822c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_status_read);
823025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
824c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
825c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
828c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
830c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
831c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 2;
832c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
833c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
834c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!sr_buf) {
835c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
836c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_buf;
837c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
838c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(sr_buf, 0, sizeof(*sr_buf));
839c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = sr_buf;
840c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_curr(req);
841c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->addr = (void *) sr_buf;
842c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->length = sizeof(*sr_buf);
843059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
844c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
845c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval)
846c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_req_send;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
848c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
849c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
850c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_req_send:
851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
852c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_buf:
853c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
854c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
855c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
856d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
857c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
858c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
860c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
861c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
862c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
863c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
864c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
865c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
866c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
867c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
868c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
870c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
8719467a9b3efdd9041202f71cc270bda827a7ec777Martin Peschke			zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104,
872c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						req);
873c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
877c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
878c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_port_reopen(unit->port, 0, 105, req);
879c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
883c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
886c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 47, req);
887c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
888c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
891c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_boxed(unit, 48, req);
892c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
893c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
896c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (fsq->word[0]) {
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
89865a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
900c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
905c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
911c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_abort_fcp_command - abort running SCSI command
912c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @old_req_id: unsigned long
913c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
914c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
915c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: integer specifying the request flags
916c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: pointer to struct zfcp_fsf_req
917c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
918c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * FIXME(design): should be watched by a timeout !!!
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
922c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						struct zfcp_adapter *adapter,
923c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						struct zfcp_unit *unit,
924c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						int req_flags)
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
927c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
9288a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
929c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
9302450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
931c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
933c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  req_flags, adapter->pool.fsf_req_abort);
934025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req))
935c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
9362abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
937c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
938c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out_error_free;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
942c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
943c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
945c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
946c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_abort_fcp_command_handler;
947c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
948c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_handle = (u64) old_req_id;
950c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
951c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
952c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
953c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
954c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
955c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout_error_free:
956c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
957c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
958c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
959c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
960c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
963c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
965c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
966c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_ct *send_ct = req->data;
967c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = send_ct->port;
968c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
970c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_ct->status = -EINVAL;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
972c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
977c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_ct_response(req);
978c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_ct->status = 0;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
981c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			zfcp_test_link(port);
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
988c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
993c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
996c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(port, 49, req);
997c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
998c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1000c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
1001c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, 106, req);
1002c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GENERIC_COMMAND_REJECTED:
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
1007c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
1012c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (send_ct->handler)
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_ct->handler(send_ct->handler_data);
1014c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1016c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req,
1017c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				struct scatterlist *sg_req,
1018c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				struct scatterlist *sg_resp, int max_sbals)
1019c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
1020c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int bytes;
1021c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1022c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1023c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					sg_req, max_sbals);
1024c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes <= 0)
1025c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -ENOMEM;
1026c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_buf_length = bytes;
1027c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
1028c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1029c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1030c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					sg_resp, max_sbals);
1031c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes <= 0)
1032c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -ENOMEM;
1033c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.resp_buf_length = bytes;
1034c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1035c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1039c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1040c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @ct: pointer to struct zfcp_send_ct with data for request
1041c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
1042c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: if non-null the Generic Service request sent within ERP
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1044c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
1045c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		     struct zfcp_erp_action *erp_action)
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1047c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = ct->port;
1048c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = port->adapter;
1049c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1050c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1052d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1053c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1054c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1056c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
1057c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP, pool);
1058025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1059c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		ret = PTR_ERR(req);
1060c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
10613f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt	}
10623f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt
1063c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp,
1064c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   FSF_MAX_SBALS_PER_REQ);
1065553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (ret)
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1068c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_ct_handler;
1069c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = port->handle;
1070c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.service_class = FSF_CLASS_3;
1071c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.timeout = ct->timeout;
1072c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = ct;
1073c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1074c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_san_dbf_event_ct_request(req);
1075c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1076c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (erp_action) {
1077c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = req;
1078c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->erp_action = erp_action;
1079287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt		zfcp_fsf_start_erp_timer(req);
1080c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	} else
1081c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1083c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_req_send(req);
1084c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1085c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1087c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1089c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_send:
1090c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
1091c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (erp_action)
1092c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
1093c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1094d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
1095c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ret;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1098c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1100c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_els *send_els = req->data;
1101c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = send_els->port;
1102c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1104c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_els->status = -EINVAL;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1106c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
1111c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_els_response(req);
1112c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_els->status = 0;
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
1115c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]){
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
112064b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann			if (port && (send_els->ls_code != ZFCP_LS_ADISC))
112164b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann				zfcp_test_link(port);
1122c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/*fall through */
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_RETRY_IF_POSSIBLE:
1125c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ELS_COMMAND_REJECTED:
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1135c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1137c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SBAL_MISMATCH:
1138c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* should never occure, avoided in zfcp_fsf_send_els */
1139c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1141c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
1145aa551daf5cc6fb6c6e09bb993737f9cd46dc7145Heiko Carstens	if (send_els->handler)
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_els->handler(send_els->handler_data);
1147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1149c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1150c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @els: pointer to struct zfcp_send_els with data for the command
1152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig */
1153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_els(struct zfcp_send_els *els)
1154c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
1155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = els->adapter;
1157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
1158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
1159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&els->port->status) &
1161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
1162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
1163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
11652450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
1168c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP, NULL);
1169025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1170c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		ret = PTR_ERR(req);
1171c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1172c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1173c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_setup_sbals(req, els->req, els->resp,
1175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   FSF_MAX_SBALS_PER_ELS_REQ);
1176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1177c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
1178c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1179c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
1180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_els_handler;
1181c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->d_id = els->d_id;
1182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->service_class = FSF_CLASS_3;
1183c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->timeout = 2 * R_A_TOV;
1184c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = els;
1185c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1186c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_san_dbf_event_els_request(req);
1187c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1188c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1189c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_req_send(req);
1190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1191c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
1192c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1193c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
1194c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_send:
1196c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
1197c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1198c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
1199c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ret;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
120652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1207c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1208c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1209d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
12102450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1213c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_EXCHANGE_CONFIG_DATA,
1214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1216025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1217c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1218c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
122252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
122352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1225c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.config.feature_selection =
1226aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_CFDC |
1227aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_LUN_SHARING |
12289eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin			FSF_FEATURE_NOTIFICATION_LOST |
1229aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_UPDATE_ALERT;
1230c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1231c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_config_data_handler;
1232c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1234287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1235c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1237c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1240c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1241d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
124252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
124352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1245c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
1246c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				       struct fsf_qtcb_bottom_config *data)
124752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
124852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	volatile struct qdio_buffer_element *sbale;
1249c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
1250c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1251c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1252d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1254c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
1257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  0, NULL);
1258025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
126152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
126252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
126452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
126552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1266c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_config_data_handler;
126752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1268c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.config.feature_selection =
126952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_CFDC |
127052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_LUN_SHARING |
127152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_NOTIFICATION_LOST |
127252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_UPDATE_ALERT;
127352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
127452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
1275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->data = data;
127652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1280d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
1281553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!retval)
1282c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
1283c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
128452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1285c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
128652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data - request information about local port
1292aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin * @erp_action: ERP action for the adapter for which port data is requested
1293c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1295c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1298c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
129952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1302553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
130352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1305d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
13062450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
1309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1311025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1314aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
1315aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
131752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
131852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_port_data_handler;
1321c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1322c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
132352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1324287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1327c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
132852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		erp_action->fsf_req = NULL;
132952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
1330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1331d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
133252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
133352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
133452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
133552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig/**
133652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig * zfcp_fsf_exchange_port_data_sync - request information about local port
1337c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
1338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @data: pointer to struct fsf_qtcb_bottom_port
1339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
134052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig */
1341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
1342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				     struct fsf_qtcb_bottom_port *data)
134352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
134452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	volatile struct qdio_buffer_element *sbale;
1345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
1346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
134752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1348553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
134952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
135052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1351d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
13522450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
1353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
1356c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  NULL);
1357025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1359c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
136252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
1363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->data = data;
136452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
136652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
136752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
136852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_port_data_handler;
1370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1373d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
1374553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!retval)
1375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
1376c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
1377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1382c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1384c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_plogi *plogi;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_ALREADY_OPEN:
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1395c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1398c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
1399ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "Not enough FCP adapter resources to open "
1400ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "remote port 0x%016Lx\n", port->wwpn);
1401c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_failed(port, 31, req);
1402c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
1411c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_warn(&req->adapter->ccw_device->dev,
1412ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "Remote port 0x%016Lx could not be opened\n",
1413ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 port->wwpn);
1414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_port_failed(port, 32, req);
1415c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
1423d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1424d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
1425d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1441c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN)
1442c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			break;
1443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1444c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
1445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
1446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			if (plogi->serv_param.wwpn != port->wwpn)
1447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID,
1448c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						  &port->status);
1449c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			else {
1450c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				port->wwnn = plogi->serv_param.wwnn;
1451c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_fc_plogi_evaluate(port, plogi);
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
1456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1464c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_port - create and send open port request
1466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1467c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1469c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1476d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1478c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1480c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_OPEN_PORT_WITH_DID,
1482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1483c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1484025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1493c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_port_handler;
1494c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.d_id = erp_action->port->d_id;
1495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1496c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1497c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
1499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1500287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1501c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1507d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1515c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1518c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1520c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, 107, req);
1521c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
1526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_modify_port_status(port, 33, req,
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1532c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1536c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_port - create and send close port request
1538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1539c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1545c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1546c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1547c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1548d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1549c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1550c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1551c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1552c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
1553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1554c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1555025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1556c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1558c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1560c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1564c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_port_handler;
1565c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1566c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1567c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1568c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1569c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
1570c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1571287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1572c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1574c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1577c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1578d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1582c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1584c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1585c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1588c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1593c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, 108, req);
1594c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1597c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1600c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(port, 50, req);
1601c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1602c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
16035c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		/* can't use generic zfcp_erp_modify_port_status because
16045c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
16055c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
16065c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		list_for_each_entry(unit, &port->unit_list_head, list)
16075c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
16085c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt					  &unit->status);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1613c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1615c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
1625c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1626c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					  &unit->status);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1629c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1633c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1634c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_physical_port - close physical port
1635c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1636c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1638c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1641c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1642c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1643c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1644c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1645d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1646c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1649c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT,
1650c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1651c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1652025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1653c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1654c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1655c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1657c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
1658c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1659c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1662c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1663c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1664c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_physical_port_handler;
1665c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1666c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
1667c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&erp_action->port->status);
1668c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1669287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1670c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1672c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1675c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1676d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1680c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1682c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
1683c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
1684c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
1685c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
1686c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_queue_designator *queue_designator =
1687c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&header->fsf_status_qual.fsf_queue_designator;
1688aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	int exclusive, readwrite;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1690c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1694b64ddf96456cde17be22bf74cafed381a29d58baHeiko Carstens			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1702c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req);
1703c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1707c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
1709553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1712c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 51, req);
1713c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
1717c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0])
1718553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			dev_warn(&adapter->ccw_device->dev,
1719ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "LUN 0x%Lx on port 0x%Lx is already in "
1720ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "use by CSS%d, MIF Image ID %x\n",
1721553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt				 unit->fcp_lun,
1722553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt				 unit->port->wwpn,
1723ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->cssid,
1724ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->hla);
1725c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else
1726553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			zfcp_act_eval_err(adapter,
1727553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					  header->fsf_status_qual.word[2]);
1728c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_access_denied(unit, 60, req);
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
1731c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
1734c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&adapter->ccw_device->dev,
1735ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "No handle is available for LUN "
1736ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "0x%016Lx on port 0x%016Lx\n",
1737553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			 unit->fcp_lun, unit->port->wwpn);
1738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_failed(unit, 34, req);
1739c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
1740c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_INVALID_COMMAND_OPTION:
1741c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
174665a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1749c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
1757aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1758aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
1759aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
1760aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
1761aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			exclusive = (bottom->lun_access_info &
1762aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_EXCLUSIVE);
1763aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			readwrite = (bottom->lun_access_info &
1764aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
1765aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
1773c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_info(&adapter->ccw_device->dev,
1774ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "SCSI device at LUN 0x%016Lx on port "
1775ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "0x%016Lx opened read-only\n",
1776553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					 unit->fcp_lun, unit->port->wwpn);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
1780c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1781ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Exclusive read-only access not "
1782ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, "
1783ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"port 0x%016Lx)\n",
1784553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					unit->fcp_lun, unit->port->wwpn);
1785c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_failed(unit, 35, req);
1786c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1787c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, 80, req);
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
1789c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1790ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Shared read-write access not "
1791ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, port "
1792ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"0x%016Lx\n)",
1793553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					unit->fcp_lun, unit->port->wwpn);
1794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_failed(unit, 36, req);
1795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, 81, req);
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1802c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1806c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1807c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_unit - open unit
1808c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1809c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1811c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1814c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1815c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1816c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1817c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1818d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1819c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1822c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN,
1823c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1824c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1825025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1826c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1827c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1828c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1830c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1834c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1835c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
1836c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_unit_handler;
1837c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
1838c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1839c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1840c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1841c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
1842c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
1843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1844c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1846287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1847c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1849c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1852c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1853d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1857c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1864c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
1866c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req);
1867c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
1870c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, 111, req);
1871c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
1874c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 52, req);
1875c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1876c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
1879c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (req->qtcb->header.fsf_status_qual.word[0]) {
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
188165a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1882c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1884c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1892c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1897c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_unit - close zfcp unit
1898c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_unit
1899c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1901c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
1904c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1905c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1906c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1908d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
1909c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1911c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
1912c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1913c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1914025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1915c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1916c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1917c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1919c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
1920c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1923c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1924c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = erp_action->unit->handle;
1925c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_unit_handler;
1926c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
1927c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1928c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1929c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
1930fdf234527a070f6fc89f3ec5ee4ae1b263e59939Christof Schmitt
1931287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1933c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval) {
1934c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
1935c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
1936c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1937c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
1938d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
1939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1942c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmittstatic void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
1943c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
1944c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat_rec->sum += lat;
1945c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->min = min(lat_rec->min, lat);
1946c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->max = max(lat_rec->max, lat);
1947c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt}
1948c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
1950c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
1951c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct fsf_qual_latency_info *lat_inf;
1952c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct latency_cont *lat;
1953c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->unit;
1954c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	unsigned long flags;
1955c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1956c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
1957c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1958c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->bottom.io.data_direction) {
1959c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_READ:
1960c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.read;
1961c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
1962c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_WRITE:
1963c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.write;
1964c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
1965c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_CMND:
1966c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.cmd;
1967c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
1968c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	default:
1969c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		return;
1970c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	}
1971c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
1972c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	spin_lock_irqsave(&unit->latencies.lock, flags);
1973c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
1974c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
1975c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat->counter++;
1976c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock_irqrestore(&unit->latencies.lock, flags);
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1979c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1981c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct scsi_cmnd *scpnt = req->data;
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
1983c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
1985f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1988553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (unlikely(!scpnt))
1989c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
1990553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
1991c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&req->adapter->abort_lock, flags);
1992c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1993c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
1994feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_SOFT_ERROR);
1995feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_driver_byte(scpnt, SUGGEST_RETRY);
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1999c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
2000feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_ERROR);
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2004feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann	set_msg_byte(scpnt, COMMAND_COMPLETE);
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2008c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
2009c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_latency(req);
2010c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
2012c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fcp_rsp_info[3] == RSP_CODE_GOOD)
2013feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_OK);
2014c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2015feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
20166f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
2021c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
2022c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			  fcp_rsp_iu->fcp_rsp_len;
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20269d058ecfd444d247b7448e0ef44647514d91a4f2FUJITA Tomonori		memcpy(scpnt->sense_buffer,
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
20317936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
20327936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
20337936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		    scpnt->underflow)
2034feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2036c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
20378a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
2038c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req);
20398a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
2040c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req);
20418a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
2042c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req);
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2052c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&req->adapter->abort_lock, flags);
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2055c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
2058c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
2059f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
2062c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	     (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2063c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
2064c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2065c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2066c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2067c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
2068c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2069c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit;
2070c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
2071c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2072c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
2073c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->data;
2074c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2075c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->unit;
2076c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2077c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2080c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (header->fsf_status) {
2081c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_HANDLE_MISMATCH:
2082c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
2083c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req);
2084c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2085c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2086c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_FCPLUN_NOT_VALID:
2087c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_HANDLE_NOT_VALID:
2088c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, 113, req);
2089c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2091c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2092c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2094c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ACCESS_DENIED:
2095c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
2096c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2097c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_DIRECTION_INDICATOR_NOT_VALID:
2098c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2099ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect direction %d, unit 0x%016Lx on port "
2100ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%016Lx closed\n",
2101c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.data_direction,
2102c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			unit->fcp_lun, unit->port->wwpn);
2103c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req);
2104c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2105c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2106c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_CMND_LENGTH_NOT_VALID:
2107c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2108ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect CDB length %d, unit 0x%016Lx on "
2109ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"port 0x%016Lx closed\n",
2110c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.fcp_cmnd_length,
2111c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			unit->fcp_lun, unit->port->wwpn);
2112c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req);
2113c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2114c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2115c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_BOXED:
2116c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_port_boxed(unit->port, 53, req);
2117c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2118c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2120c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_BOXED:
2121c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_unit_boxed(unit, 54, req);
2122c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2123c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2124c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2125c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
2126c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0] ==
2127c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
2128c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_test_link(unit->port);
2129c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2132c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
2133c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
2134c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_ctm_handler(req);
2135c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else {
2136c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_command_task_handler(req);
2137c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->unit = NULL;
2138c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_unit_put(unit);
2139c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2142c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2143c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
2144c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: adapter where scsi command is issued
2145c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: unit where command is sent to
2146c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @scsi_cmnd: scsi command to be sent
2147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @timer: timer to be started when request is initiated
2148c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: flags for fsf_request
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2150c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
2151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   struct zfcp_unit *unit,
2152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   struct scsi_cmnd *scsi_cmnd,
2153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				   int use_timer, int req_flags)
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
2156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
2157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned int sbtype;
2158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int real_bytes, retval = -EIO;
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
21652450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
2166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2168c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2169025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2170c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
2171c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2172c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2173c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_get(unit);
2175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->unit = unit;
2176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = scsi_cmnd;
2177c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2178c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2179c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2181c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2183c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2184c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
2185c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2186c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
2187c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * set depending on data direction:
2188c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in SBALE (SB Type)
2189c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in QTCB
2190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in FCP_CMND IU
2191c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
2192c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (scsi_cmnd->sc_data_direction) {
2193c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_NONE:
2194c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2197c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_FROM_DEVICE:
2198c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2199c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
2200c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->rddata = 1;
2201c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_TO_DEVICE:
2203c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2204c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_WRITE;
2205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->wddata = 1;
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2207c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_BIDIRECTIONAL:
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2209c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EIO;
2210c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2213c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely((scsi_cmnd->device->simple_tags) ||
2214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		   ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
2215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
2216c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
2217c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2218c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = UNTAGGED;
22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2220c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
2221c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->add_fcp_cdb_length =
2222c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2224c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
222545633fdc9615f9fd2a0ae18e301562298b15abf3Christof Schmitt
2226c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
2227c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t);
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
2230c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     scsi_sglist(scsi_cmnd),
2231c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     FSF_MAX_SBALS_PER_REQ);
2232c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(real_bytes < 0)) {
2233c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
2234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EIO;
2235c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2236c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
2237ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"Oversize data package, unit 0x%016Lx "
2238ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"on port 0x%016Lx closed\n",
2239ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				unit->fcp_lun, unit->port->wwpn);
2240c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_erp_unit_shutdown(unit, 0, 131, req);
2241c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EINVAL;
2242c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
2243c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2246c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2248c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (use_timer)
2249c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2252c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(retval))
2253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_scsi_cmnd:
2258c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_put(unit);
2259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = NULL;
2261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
2262c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
2263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_ctm - send SCSI task management command
2268c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp-adapter
2269c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
2270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @tm_flags: unsigned byte for task management flags
2271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: int request flags
2272c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct fsf_req, NULL otherwise
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2274c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
2275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_unit *unit,
2276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   u8 tm_flags, int req_flags)
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
2279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2282c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2283c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2284c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2286c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_lock(&adapter->req_q.lock);
22872450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!zfcp_fsf_sbal_available(adapter))
2288c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2289c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2290c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2291025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req))
2292c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2294c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2295c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
2296c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2297c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2298c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = 	sizeof(struct fcp_cmnd_iu) +
2302c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						sizeof(fcp_dl_t);
2303c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2305c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
2309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->task_management_flags = tm_flags;
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
2314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
2318c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
2319c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	spin_unlock(&adapter->req_q.lock);
2320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
2321c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2323c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
2324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb->header.fsf_status != FSF_GOOD)
2326c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_control_file - control file upload/download
2331c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
2332c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc
2333c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2335c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_fsf_cfdc *fsf_cfdc)
23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct qdio_buffer_element *sbale;
2339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
2341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int direction, retval = -EIO, bytes;
2342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
2344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EOPNOTSUPP);
2345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (fsf_cfdc->command) {
2347c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
2348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_WRITE;
2349c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_UPLOAD_CONTROL_FILE:
2351c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_READ;
2352c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
2354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EINVAL);
2355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2357d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_lock_bh(&adapter->req_q.lock);
2358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
2359c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL);
2362025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EPERM;
2364c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_control_file_handler;
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= direction;
23718a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
2373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
2374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->option = fsf_cfdc->option;
23758a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2376c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
2377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					FSF_MAX_SBALS_PER_REQ);
2378c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes != ZFCP_CFDC_MAX_SIZE) {
2379c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
2380c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
2381c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2382c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2384c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
2387d4538817287e56abc938900886301a5bdfafbfcdChristof Schmitt	spin_unlock_bh(&adapter->req_q.lock);
23888a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!retval) {
2390c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
2391c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
2392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return req;
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2394c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ERR_PTR(retval);
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2396