zfcp_fsf.c revision 5ffd51a5e495a2a002efd523aef0001912b080bd
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
9ecf39d42129767c0b4b4a6cf4997c1219c860934Christof Schmitt#define KMSG_COMPONENT "zfcp"
10ecf39d42129767c0b4b4a6cf4997c1219c860934Christof Schmitt#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11ecf39d42129767c0b4b4a6cf4997c1219c860934Christof Schmitt
120997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#include <linux/blktrace_api.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "zfcp_ext.h"
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1563caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt#define ZFCP_REQ_AUTO_CLEANUP	0x00000002
1663caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt#define ZFCP_REQ_NO_QTCB	0x00000008
1763caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt
18287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_request_timeout_handler(unsigned long data)
19287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
20287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
215ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
225ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig				"fsrth_1", NULL);
23287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
24287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
25287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
26287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt				 unsigned long timeout)
27287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
28287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
29287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.data = (unsigned long) fsf_req->adapter;
30287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.expires = jiffies + timeout;
31287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	add_timer(&fsf_req->timer);
32287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
33287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
34287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmittstatic void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req)
35287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt{
36287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	BUG_ON(!fsf_req->erp_action);
37287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.function = zfcp_erp_timeout_handler;
38287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
39287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	fsf_req->timer.expires = jiffies + 30 * HZ;
40287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	add_timer(&fsf_req->timer);
41287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt}
42287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* association between FSF command and FSF QTCB type */
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 fsf_qtcb_type[] = {
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND,
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND,
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
61553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
62c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	u16 subtable = table >> 16;
63553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	u16 rule = table & 0xffff;
64ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
65553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
66ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	if (subtable && subtable < ARRAY_SIZE(act_type))
67553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		dev_warn(&adapter->ccw_device->dev,
68ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "Access denied according to ACT rule type %s, "
69ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "rule %d\n", act_type[subtable], rule);
70553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
71553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
72553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
73553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					struct zfcp_port *port)
74553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
75553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct fsf_qtcb_header *header = &req->qtcb->header;
76553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	dev_warn(&req->adapter->ccw_device->dev,
77ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		 "Access denied to port 0x%016Lx\n",
787ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		 (unsigned long long)port->wwpn);
79553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
80553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
815ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig	zfcp_erp_port_access_denied(port, "fspad_1", req);
82553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
83553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
84553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
85553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
86553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					struct zfcp_unit *unit)
87553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
88553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct fsf_qtcb_header *header = &req->qtcb->header;
89553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	dev_warn(&req->adapter->ccw_device->dev,
90ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		 "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
917ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		 (unsigned long long)unit->fcp_lun,
927ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		 (unsigned long long)unit->port->wwpn);
93553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
94553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
955ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig	zfcp_erp_unit_access_denied(unit, "fsuad_1", req);
96553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
97553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
98553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
99553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmittstatic void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
100553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
101ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt	dev_err(&req->adapter->ccw_device->dev, "FCP device not "
102ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		"operational because of an unsupported FC class\n");
1035ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig	zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req);
104553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
105553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt}
106553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
107c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
108c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_free - free memory used by fsf request
109c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_req: pointer to struct zfcp_fsf_req
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligvoid zfcp_fsf_req_free(struct zfcp_fsf_req *req)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
113c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->pool)) {
114c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		mempool_free(req, req->pool);
115dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
116dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
117dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens
118c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb) {
119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req);
120dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens		return;
121dd52e0eaf891cd85bf2ca057c15ed6bfd76db4e6Heiko Carstens	}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
125c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
126c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
127c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
128869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Never ever call this without shutting down the adapter first.
129869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Otherwise the adapter would continue using and corrupting s390 storage.
130869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * Included BUG_ON() call to ensure this is done.
131869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke * ERP is supposed to be the only user of this function.
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1336fcc47111ae14f284007e1b9a5002babb01d913cSwen Schilligvoid zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
135c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req, *tmp;
136fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	unsigned long flags;
1376fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig	LIST_HEAD(remove_queue);
138869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	unsigned int i;
139fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
140c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
141fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_lock_irqsave(&adapter->req_list_lock, flags);
142869b2b444c58302e3233ce0b671fabf28135a37dMartin Peschke	for (i = 0; i < REQUEST_LIST_SIZE; i++)
1436fcc47111ae14f284007e1b9a5002babb01d913cSwen Schillig		list_splice_init(&adapter->req_list[i], &remove_queue);
144fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
145fea9d6c7bcd8ff1d60ff74f27ba483b3820b18a3Volker Sameske
146c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_for_each_entry_safe(req, tmp, &remove_queue, list) {
147c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		list_del(&req->list);
148c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
149c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_complete(req);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port;
158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int d_id = sr_buf->d_id & ZFCP_DID_MASK;
159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned long flags;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&zfcp_data.config_lock, flags);
162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_for_each_entry(port, &adapter->port_list_head, list)
163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (port->d_id == d_id) {
164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1655ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig			zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
168c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1715ffd51a5e495a2a002efd523aef0001912b080bdSwen Schilligstatic void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
172c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					 struct fsf_link_down_info *link_down)
173aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin{
174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
175698ec01635819c5ae60090bb4efcbeffc41642fbMartin Peschke
176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
177ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin		return;
178ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
179ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin	atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
180ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
181c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!link_down)
1822f8f3ed5fc566700cf45d422f4cf1624bd123d93Andreas Herrmann		goto out;
183ee69ab7af3cd68423e389272e1276718d4cd8ebcMaxim Shchetynin
184aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	switch (link_down->error_code) {
185aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_LIGHT:
186c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
187ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "There is no light signal from the local "
188ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "fibre channel cable\n");
189aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
190aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WRAP_PLUG:
191c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
192ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "There is a wrap plug instead of a fibre "
193ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "channel cable\n");
194aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
195aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP:
196c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
197ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The adjacent fibre channel node does not "
198ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "support FCP\n");
199aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
200aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FIRMWARE_UPDATE:
201c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
202ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP device is suspended because of a "
203ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "firmware update\n");
204553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		break;
205aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_INVALID_WWPN:
206c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
207ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP device detected a WWPN that is "
208ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "duplicate or not valid\n");
209aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
210aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
212ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The fibre channel fabric does not support NPIV\n");
213aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
214aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FCP_RESOURCES:
215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
216ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP adapter cannot support more NPIV ports\n");
217aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
218aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
219c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
220ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The adjacent switch cannot support "
221ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "more NPIV ports\n");
222aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
223aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
224c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
225ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The FCP adapter could not log in to the "
226ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "fibre channel fabric\n");
227aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
228aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
230ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The WWPN assignment file on the FCP adapter "
231ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been damaged\n");
232aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
233aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
235ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The mode table on the FCP adapter "
236ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been damaged\n");
237aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
238aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
239c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
240ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "All NPIV ports on the FCP adapter have "
241ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "been assigned\n");
242aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
243aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	default:
244c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
245ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The link between the FCP adapter and "
246ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "the FC fabric is down\n");
247aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
248c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
249c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_erp_adapter_failed(adapter, id, req);
250aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin}
251aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
252c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
254c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_link_down_info *ldi =
256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		(struct fsf_link_down_info *) &sr_buf->payload;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
258c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (sr_buf->status_subtype) {
259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
2605ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
262c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_FDISC_FAILED:
2635ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
265c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
2665ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL);
267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	};
268c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
272c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
273c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf = req->data;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf);
277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		mempool_free(sr_buf, adapter->pool.data_status_read);
278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
282c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
284c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (sr_buf->status_type) {
285c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_PORT_CLOSED:
286c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_port_closed(req);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
288c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_INCOMING_ELS:
289c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fc_incoming_els(req);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
291c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_SENSE_DATA_AVAIL:
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
293c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
294ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt		dev_warn(&adapter->ccw_device->dev,
295ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The error threshold for checksum statistics "
296ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "has been exceeded\n");
29757069386699994c3e67042fc4928c418f3a39e01Swen Schillig		zfcp_hba_dbf_event_berr(adapter, req);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_LINK_DOWN:
300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_link_down(req);
301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
302c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_LINK_UP:
303c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_info(&adapter->ccw_device->dev,
304ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "The local link has been restored\n");
305c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* All ports should be marked as ready to run again */
3065ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL,
307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_STATUS_COMMON_RUNNING,
308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_SET);
309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter,
310c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
311c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_COMMON_ERP_FAILED,
3125ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig					"fssrh_2", req);
313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_NOTIFICATION_LOST:
315c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
3165ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig			zfcp_erp_adapter_access_changed(adapter, "fssrh_3",
3175ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig							req);
318c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
319c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			schedule_work(&adapter->scan_work);
320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
321c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_CFDC_UPDATED:
3225ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req);
323c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->adapter_features = sr_buf->payload.word[0];
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
332c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	atomic_inc(&adapter->stat_miss);
333b7f15f3c94196accac799727502ed88a029ae7efSwen Schillig	queue_work(zfcp_data.work_queue, &adapter->stat_work);
334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
337c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status_qual.word[0]) {
339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_FCP_RSP_AVAILABLE:
340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_NO_RETRY_POSSIBLE:
342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_COMMAND_ABORTED:
345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
347c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SQ_NO_RECOM:
348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
349ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter reported a problem "
350ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"that cannot be recovered\n");
3515ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
352c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* all non-return stats set FSFREQ_ERROR*/
355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
361c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
364c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_UNKNOWN_COMMAND:
365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
366ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter does not recognize the command 0x%x\n",
367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->header.fsf_command);
3685ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req);
369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_fsfstatus_qual_eval(req);
373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
378c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
379c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
380c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
381c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_response(req);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
387c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->prefix.prot_status) {
392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_GOOD:
393c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_FSF_STATUS_PRESENTED:
394c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
395c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_QTCB_VERSION_ERROR:
396c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
397ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"QTCB version 0x%x not supported by FCP adapter "
398ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
399ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			psq->word[0], psq->word[1]);
4005ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req);
401c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
402c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_ERROR_STATE:
403c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_SEQ_NUMB_ERROR:
4045ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
405c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_RETRY;
406c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
407c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_UNSUPP_QTCB_TYPE:
408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
409ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The QTCB type is not supported by the FCP adapter\n");
4105ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req);
411c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_HOST_CONNECTION_INITIALIZING:
413c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
415c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
416c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_DUPLICATE_REQUEST_ID:
417c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
418ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%Lx is an ambiguous request identifier\n",
419c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(unsigned long long)qtcb->bottom.support.req_handle);
4205ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req);
421c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
422c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_LINK_DOWN:
4235ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_fsf_link_down_info_eval(req, "fspse_5",
4245ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig					     &psq->link_down_info);
425c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* FIXME: reopening adapter now? better wait for link up */
4265ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
427c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
428c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PROT_REEST_QUEUE:
429c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* All ports should be marked as ready to run again */
4305ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL,
431c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_STATUS_COMMON_RUNNING,
432c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					       ZFCP_SET);
433c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_erp_adapter_reopen(adapter,
434c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
4355ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig					ZFCP_STATUS_COMMON_ERP_FAILED,
4365ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig					"fspse_8", req);
437c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
438c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
439c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
440ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%x is not a valid transfer protocol status\n",
441c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			qtcb->prefix.prot_status);
4425ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
444c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_ERROR;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
448c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_req_complete - process completion of a FSF request
449c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_req: The FSF request that has been completed.
450c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig *
451c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * When a request has been completed either from the FCP adapter,
452c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * or it has been dismissed due to a queue shutdown, this function
453c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * is called to process the completion status and trigger further
454c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * events related to the FSF request.
455c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig */
456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligvoid zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_status_read_handler(req);
460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
461c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
463c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	del_timer(&req->timer);
464c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_protstatus_eval(req);
465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_fsfstatus_eval(req);
466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler(req);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->erp_action)
469287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt		zfcp_erp_notify(req->erp_action, 0);
470c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* notify initiator waiting for the requests completion */
476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * FIXME: Race! We must not access fsf_req here as it might have been
478c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
479c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * flag. It's an improbable case. But, we have the same paranoia for
480c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * the cleanup flag already.
481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * Might better be handled using complete()?
482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * (setting the flag and doing wakeup ought to be atomic
483c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *  with regard to checking the flag as long as waitqueue is
484c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *  part of the to be released structure)
485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
486c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wake_up(&req->completion_wq);
487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
491c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_config *bottom;
492c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
493c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.config;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
497c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->data)
498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(req->data, bottom, sizeof(*bottom));
499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
500c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
501c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
502c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_speed(shost) = bottom->fc_link_speed;
504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
505c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->hydra_version = bottom->adapter_type;
507c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->timer_ticks = bottom->timer_interval;
508c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
509c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (fc_host_permanent_port_name(shost) == -1)
510c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
512c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (bottom->fc_topology) {
513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_P2P:
514c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
515c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
516c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
517c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_PTP;
518c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
519c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_FABRIC:
520c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
521c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
522c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_TOPO_AL:
523c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
524c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
525c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
526ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Unknown or unsupported arbitrated loop "
527ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"fibre channel topology detected\n");
5285ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req);
529c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
531c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
535c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
536553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt{
537553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	struct zfcp_adapter *adapter = req->adapter;
538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
539c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
541553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt
542c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
545c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->fsf_lic_version = bottom->lic_version;
546c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->adapter_features = bottom->adapter_features;
547c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->connection_features = bottom->connection_features;
548c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_wwpn = 0;
549c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_wwnn = 0;
550c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	adapter->peer_d_id = 0;
5518a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
552c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
554c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (zfcp_fsf_exchange_config_evaluate(req))
555c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
557c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
558c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
559ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"FCP adapter maximum QTCB size (%d bytes) "
560ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"is too small\n",
561ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				bottom->max_qtcb_size);
5625ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig			zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req);
563c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			return;
564c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
565c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
566c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
568c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
569c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_node_name(shost) = 0;
570c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_name(shost) = 0;
571c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_id(shost) = 0;
572c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
573c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
574c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->hydra_version = 0;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
576c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
577c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&adapter->status);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5795ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_fsf_link_down_info_eval(req, "fsecdh2",
580c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
582c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
5835ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req);
584c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
585c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
587c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
588c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->hardware_version = bottom->hardware_version;
589c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(fc_host_serial_number(shost), bottom->serial_number,
590c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       min(FC_SERIAL_NUMBER_SIZE, 17));
591c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		EBCASC(fc_host_serial_number(shost),
592c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       min(FC_SERIAL_NUMBER_SIZE, 17));
593c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
595c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
596c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
597ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter only supports newer "
598ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"control block versions\n");
5995ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req);
600c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
601c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
602c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
603c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&adapter->ccw_device->dev,
604ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"The FCP adapter only supports older "
605ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"control block versions\n");
6065ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req);
607c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
608c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
610c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
611c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
612c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
613c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port;
614c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct Scsi_Host *shost = adapter->scsi_host;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
616c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->data)
617c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		memcpy(req->data, bottom, sizeof(*bottom));
6189eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin
619c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
620c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = bottom->wwpn;
621c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
622c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
623c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
624c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fc_host_supported_speeds(shost) = bottom->supported_speed;
625c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
627c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
628c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
629c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb *qtcb = req->qtcb;
630c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
631c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
632c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
633c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
634c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (qtcb->header.fsf_status) {
635c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GOOD:
636c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
637c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
638c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
639c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_exchange_port_evaluate(req);
6405ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_fsf_link_down_info_eval(req, "fsepdh1",
641c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			&qtcb->header.fsf_status_qual.link_down_info);
642aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		break;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
644c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
645d26ab06ede83287f99067fee3034c5455a75faf9Swen Schillig
646c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
647dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	__releases(&adapter->req_q_lock)
648dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	__acquires(&adapter->req_q_lock)
649c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
650dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	struct zfcp_qdio_queue *req_q = &adapter->req_q;
651c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	long ret;
652c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
653dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	if (atomic_read(&req_q->count) <= -REQUEST_LIST_SIZE)
654dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt		return -EIO;
655dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	if (atomic_read(&req_q->count) > 0)
656dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt		return 0;
657dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt
658dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	atomic_dec(&req_q->count);
6590406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
660c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = wait_event_interruptible_timeout(adapter->request_wq,
661dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt					atomic_read(&req_q->count) >= 0,
662dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt					5 * HZ);
663dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	spin_lock_bh(&adapter->req_q_lock);
664dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt	atomic_inc(&req_q->count);
665dedbc2b3cb8404c618975bd2811c7605a4ccb51eChristof Schmitt
666c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret > 0)
667c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return 0;
6682450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl	if (!ret)
6692450d3e7b8604d0abb042817f2502cb7ee0b782fStefan Raspl		atomic_inc(&adapter->qdio_outb_full);
670c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return -EIO;
671c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
672c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
673c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool)
674c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
675c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
676c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = mempool_alloc(pool, GFP_ATOMIC);
677c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!req)
678c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
679c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(req, 0, sizeof(*req));
68088f2a977870af655296a682fe2a58c822cd25bb2Christof Schmitt	req->pool = pool;
681c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
682c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
683c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
684c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool)
685c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
686c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req_qtcb *qtcb;
687c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
688c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(pool))
689c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = mempool_alloc(pool, GFP_ATOMIC);
690c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
691c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
692c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					GFP_ATOMIC);
693c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!qtcb))
694c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
695c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
696c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(qtcb, 0, sizeof(*qtcb));
697c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.qtcb = &qtcb->qtcb;
698c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	qtcb->fsf_req.pool = pool;
699c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
700c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return &qtcb->fsf_req;
701c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
702c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
703c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
704c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						u32 fsf_cmd, int req_flags,
705c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig						mempool_t *pool)
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
70744cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
709c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
710c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_qdio_queue *req_q = &adapter->req_q;
711951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
712c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req_flags & ZFCP_REQ_NO_QTCB)
713c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_noqtcb(pool);
714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
715c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req = zfcp_fsf_alloc_qtcb(pool);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
717c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!req))
718c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
720c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (adapter->req_no == 0)
721c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->req_no++;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
723c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	INIT_LIST_HEAD(&req->list);
724c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_timer(&req->timer);
725c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	init_waitqueue_head(&req->completion_wq);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
727c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->adapter = adapter;
728c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->fsf_command = fsf_cmd;
72952bfb558d2803590f86360ec3af1750897a9c010Christof Schmitt	req->req_id = adapter->req_no;
730c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_number = 1;
731c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_first = req_q->first;
732c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbal_last = req_q->first;
733c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 1;
734c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
735c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
736c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].addr = (void *) req->req_id;
737c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
739c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req->qtcb)) {
740c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no;
741c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_id = req->req_id;
742c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.ulp_info = 26;
743c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
744c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
745c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.req_handle = req->req_id;
746c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->header.fsf_command = req->fsf_command;
747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->seq_no = adapter->fsf_req_seq_no;
748c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
749c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].addr = (void *) req->qtcb;
750c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbale[1].length = sizeof(struct fsf_qtcb);
751c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
752c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
753c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
754c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
755c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EIO);
756c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
757951f746fece2e24a26853b3872d16e9013b6fe0bChristof Schmitt
758c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
759c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
764c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
765c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
766c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
76745316a86a67934ab499dcfac44c91aa8f39c4c78Heiko Carstens	unsigned long flags;
768c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int idx;
769c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
770c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* put allocated FSF request into hash table */
77145316a86a67934ab499dcfac44c91aa8f39c4c78Heiko Carstens	spin_lock_irqsave(&adapter->req_list_lock, flags);
772c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	idx = zfcp_reqlist_hash(req->req_id);
773c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	list_add_tail(&req->list, &adapter->req_list[idx]);
77445316a86a67934ab499dcfac44c91aa8f39c4c78Heiko Carstens	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
7763765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt	req->qdio_outb_usage = atomic_read(&adapter->req_q.count);
777c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->issued = get_clock();
778c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_qdio_send(req)) {
779c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		del_timer(&req->timer);
7803765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		spin_lock_irqsave(&adapter->req_list_lock, flags);
7813765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		/* lookup request again, list might have changed */
7823765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		if (zfcp_reqlist_find_safe(adapter, req))
7833765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt			zfcp_reqlist_remove(adapter, req);
7843765138ae946e6e29b22bf15a9647c600c232639Christof Schmitt		spin_unlock_irqrestore(&adapter->req_list_lock, flags);
7855ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
786c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EIO;
787c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
788c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
789c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/* Don't increase for unsolicited status */
790c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb)
791c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		adapter->fsf_req_seq_no++;
79252bfb558d2803590f86360ec3af1750897a9c010Christof Schmitt	adapter->req_no++;
793c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
797c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
798c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_status_read - send status read request
799c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
800c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @req_flags: request flags
801c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, ERROR otherwise
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
803c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_status_read(struct zfcp_adapter *adapter)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
805c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
806c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_status_read_buffer *sr_buf;
80744cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
808c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8100406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
811c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
812c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
813c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
814c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
815c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_NO_QTCB,
816c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_status_read);
817025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
818c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
819c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
822c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
823c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
824c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
825c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = 2;
826c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
827c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
828c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!sr_buf) {
829c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
830c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_buf;
831c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
832c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memset(sr_buf, 0, sizeof(*sr_buf));
833c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = sr_buf;
834c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_curr(req);
835c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->addr = (void *) sr_buf;
836c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale->length = sizeof(*sr_buf);
837059c97d0434834d291eff94669ca2dd3eaac9d28Andreas Herrmann
838c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
839c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval)
840c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_req_send;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
842c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
844c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_req_send:
845c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	mempool_free(sr_buf, adapter->pool.data_status_read);
846c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_buf:
847c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
848c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
849c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
8500406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
852c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
853c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
854c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
855c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
856c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
857c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
858c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
860c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return;
861c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
862c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
864c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
8655ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig			zfcp_erp_adapter_reopen(unit->port->adapter, 0,
8665ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig						"fsafch1", req);
867c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
871c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fsq->word[0] == fsq->word[1]) {
8725ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig			zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req);
873c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_FCP_COMMAND_DOES_NOT_EXIST:
877c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
8805ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_boxed(unit->port, "fsafch3", req);
881c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
882c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_BOXED:
8855ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_unit_boxed(unit, "fsafch4", req);
886c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
887c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
890c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (fsq->word[0]) {
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
89265a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
894c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
899c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
905c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_abort_fcp_command - abort running SCSI command
906c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @old_req_id: unsigned long
907c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
908c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: pointer to struct zfcp_fsf_req
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
91263caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt						struct zfcp_unit *unit)
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
91444cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
915c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
91663caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt	struct zfcp_adapter *adapter = unit->port->adapter;
9178a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
91892cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
91992cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	if (zfcp_fsf_req_sbal_get(adapter))
920c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
921c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
92263caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt				  0, adapter->pool.fsf_req_abort);
923633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	if (IS_ERR(req)) {
924633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig		req = NULL;
925c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
926633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	}
9272abbe866c8eb0296e3f5343bcf73e5371522a738Andreas Herrmann
928c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
929c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
930c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out_error_free;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
933c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
934c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
936c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
937c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_abort_fcp_command_handler;
938c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
940c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_handle = (u64) old_req_id;
941c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
942c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
943c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
944c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
945c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
946c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout_error_free:
947c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
948c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
95092cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
951c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
954c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
956c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
957c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_ct *send_ct = req->data;
958c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
960c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_ct->status = -EINVAL;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
962c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_GOOD:
967c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_ct_response(req);
968c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_ct->status = 0;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
971c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_ADAPTER_STATUS_AVAILABLE:
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                switch (header->fsf_status_qual.word[0]){
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
977c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                }
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                break;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case FSF_PORT_BOXED:
984c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
985c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
987c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
9885ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
989c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_GENERIC_COMMAND_REJECTED:
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SBAL_MISMATCH:
994c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
999c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (send_ct->handler)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_ct->handler(send_ct->handler_data);
1001c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100339eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmittstatic int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
100439eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt				       struct scatterlist *sg_req,
100539eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt				       struct scatterlist *sg_resp,
100639eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt				       int max_sbals)
1007c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
100839eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt	struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req);
100939eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt	u32 feat = req->adapter->adapter_features;
1010c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int bytes;
1011c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
101239eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt	if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
101339eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
101439eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		    !sg_is_last(sg_req) || !sg_is_last(sg_resp))
101539eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt			return -EOPNOTSUPP;
101639eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt
101739eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
101839eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		sbale[2].addr   = sg_virt(sg_req);
101939eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		sbale[2].length = sg_req->length;
102039eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		sbale[3].addr   = sg_virt(sg_resp);
102139eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		sbale[3].length = sg_resp->length;
102239eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
102339eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		return 0;
102439eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt	}
102539eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt
1026c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1027c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					sg_req, max_sbals);
1028c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes <= 0)
1029c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -ENOMEM;
1030c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.req_buf_length = bytes;
1031c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
1032c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1033c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1034c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					sg_resp, max_sbals);
1035c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes <= 0)
1036c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -ENOMEM;
1037c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.resp_buf_length = bytes;
1038c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1039c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return 0;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1043c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1044c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @ct: pointer to struct zfcp_send_ct with data for request
1045c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
1046c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: if non-null the Generic Service request sent within ERP
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1048c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
1049c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		     struct zfcp_erp_action *erp_action)
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10515ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_wka_port *wka_port = ct->wka_port;
10525ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_adapter *adapter = wka_port->adapter;
1053c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1054c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10560406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1057c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1058c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1060c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
1061c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP, pool);
1062025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1063c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		ret = PTR_ERR(req);
1064c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
10653f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt	}
10663f0ca62add34010241db682e63bb68ba765bf4a9Christof Schmitt
106739eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt	ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp,
106839eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt					  FSF_MAX_SBALS_PER_REQ);
1069553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (ret)
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed_send;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1072c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_ct_handler;
10735ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->qtcb->header.port_handle = wka_port->handle;
1074c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.service_class = FSF_CLASS_3;
1075c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.timeout = ct->timeout;
1076c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = ct;
1077c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1078c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_san_dbf_event_ct_request(req);
1079c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1080c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (erp_action) {
1081c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = req;
1082c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->erp_action = erp_action;
1083287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt		zfcp_fsf_start_erp_timer(req);
1084c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	} else
1085c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1087c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_req_send(req);
1088c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1089c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1093c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_send:
1094c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
1095c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (erp_action)
1096c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
1097c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
10980406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1099c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ret;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1102c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1104c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_send_els *send_els = req->data;
1105c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = send_els->port;
1106c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1108c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	send_els->status = -EINVAL;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1110c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
1115c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_san_dbf_event_els_response(req);
1116c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		send_els->status = 0;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
1119c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]){
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
112464b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann			if (port && (send_els->ls_code != ZFCP_LS_ADISC))
112564b29a130901d5b8578e9f602cf2dae56aaff224Andreas Herrmann				zfcp_test_link(port);
1126c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/*fall through */
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_RETRY_IF_POSSIBLE:
1129c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ELS_COMMAND_REJECTED:
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PAYLOAD_SIZE_MISMATCH:
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_REQUEST_SIZE_TOO_LARGE:
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_RESPONSE_SIZE_TOO_LARGE:
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1139c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1141c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SBAL_MISMATCH:
1142c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* should never occure, avoided in zfcp_fsf_send_els */
1143c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1145c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_fsfstatus:
1149aa551daf5cc6fb6c6e09bb993737f9cd46dc7145Heiko Carstens	if (send_els->handler)
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		send_els->handler(send_els->handler_data);
1151c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1153c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1154c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1155c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @els: pointer to struct zfcp_send_els with data for the command
1156c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig */
1157c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_send_els(struct zfcp_send_els *els)
1158c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
1159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = els->adapter;
1161c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
1162c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int ret = -EIO;
1163c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1164c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&els->port->status) &
1165c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
1166c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
1167c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
11688fdf30d5429605a4c30cc515c73e5eab140035deChristof Schmitt	spin_lock_bh(&adapter->req_q_lock);
11698fdf30d5429605a4c30cc515c73e5eab140035deChristof Schmitt	if (zfcp_fsf_req_sbal_get(adapter))
1170c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1171c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
1172c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP, NULL);
1173025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		ret = PTR_ERR(req);
1175c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1177c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
117839eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt	ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2);
117944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig
1180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1181c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
1182c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1183c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
1184c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_els_handler;
1185c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->d_id = els->d_id;
1186c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->service_class = FSF_CLASS_3;
1187c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->timeout = 2 * R_A_TOV;
1188c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = els;
1189c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_san_dbf_event_els_request(req);
1191c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1192c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1193c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	ret = zfcp_fsf_req_send(req);
1194c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (ret)
1195c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_send;
1196c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1197c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
1198c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1199c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_send:
1200c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
1201c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
12028fdf30d5429605a4c30cc515c73e5eab140035deChristof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1203c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ret;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1206c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
120844cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1209c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
121052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
12130406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
121492cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	if (zfcp_fsf_req_sbal_get(adapter))
1215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1216c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1217c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_EXCHANGE_CONFIG_DATA,
1218c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1219c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1220025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1221c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1222c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1225c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
122652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
122752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.config.feature_selection =
1230aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_CFDC |
1231aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_LUN_SHARING |
12329eb69aff79264b5f35e41922df20a488c67e9ee2Maxim Shchetynin			FSF_FEATURE_NOTIFICATION_LOST |
1233aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			FSF_FEATURE_UPDATE_ALERT;
1234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1235c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_config_data_handler;
1236c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1238287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1239c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1241c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1244c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
12450406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
124652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
124752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1249c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
1250c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				       struct fsf_qtcb_bottom_config *data)
125152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
125244cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1253c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
1254c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
12560406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1258c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
1261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  0, NULL);
1262025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1263c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1264c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
126552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
126652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
126852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
126952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_config_data_handler;
127152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1272c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.config.feature_selection =
127352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_CFDC |
127452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_LUN_SHARING |
127552ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_NOTIFICATION_LOST |
127652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig			FSF_FEATURE_UPDATE_ALERT;
127752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
127852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
1279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->data = data;
128052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1281c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1282c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1283c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
12840406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1285553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!retval)
1286c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
1287c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
128852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1289c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
129052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zfcp_fsf_exchange_port_data - request information about local port
1296aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin * @erp_action: ERP action for the adapter for which port data is requested
1297c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
130144cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1302c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
130352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1304c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1306553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
130752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13090406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
131092cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	if (zfcp_fsf_req_sbal_get(adapter))
1311c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
1313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1315025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1316c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1317c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1318aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	}
1319aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1320c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
132152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
132252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1324c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_port_data_handler;
1325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1326c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
132752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1328287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1331c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
133252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		erp_action->fsf_req = NULL;
133352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	}
1334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
13350406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
133652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	return retval;
133752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig}
133852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
133952ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig/**
134052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig * zfcp_fsf_exchange_port_data_sync - request information about local port
1341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
1342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @data: pointer to struct fsf_qtcb_bottom_port
1343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
134452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig */
1345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
1346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				     struct fsf_qtcb_bottom_port *data)
134752ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig{
134844cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1349c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
1350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
135152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1352553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
135352ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig		return -EOPNOTSUPP;
135452ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
13550406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
135692cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	if (zfcp_fsf_req_sbal_get(adapter))
1357c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1359c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
1360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  NULL);
1361025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1362c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1363c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
136652ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	if (data)
1367c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->data = data;
136852ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
137052ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
137152ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
137252ef11a7170e1b8a0d5f9a42dbb43c38c335c32eSwen Schillig
1373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_exchange_port_data_handler;
1374c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
1376c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
13770406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
1378553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt	if (!retval)
1379c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
1380c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
1381c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsf_plogi *plogi;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1392c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
139344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_ALREADY_OPEN:
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1399c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1402c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&req->adapter->ccw_device->dev,
1403ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "Not enough FCP adapter resources to open "
14047ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 "remote port 0x%016Lx\n",
14057ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 (unsigned long long)port->wwpn);
14065ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_failed(port, "fsoph_1", req);
1407c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_NO_RETRY_POSSIBLE:
1414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port->handle = header->port_handle;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
1422d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1423d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  ZFCP_STATUS_COMMON_ACCESS_BOXED,
1424d736a27b7efbc835c7b83db5c1bbd41edbadf32eAndreas Herrmann		                  &port->status);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check whether D_ID has changed during open */
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: This check is not airtight, as the FCP channel does
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * not monitor closures of target port connections caused on
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the remote side. Thus, they might miss out on invalidating
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * locally cached WWPNs (and other N_Port parameters) of gone
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * target ports. So, our heroic attempt to make things safe
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * could be undermined by 'open port' response data tagged with
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * obsolete WWPNs. Another reason to monitor potential
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * connection closures ourself at least (by interpreting
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * incoming ELS' and unsolicited status). It just crosses my
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * mind that one should be able to cross-check by means of
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * another GID_PN straight after a port has been opened.
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Alternately, an ADISC/PDISC ELS should suffice, as well.
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1440c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
144139eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		if (req->qtcb->bottom.support.els1_length >=
144239eb7e9aca2a582330ddb6f1167272268e6b3965Christof Schmitt		    FSF_PLOGI_MIN_LEN) {
1443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			if (plogi->serv_param.wwpn != port->wwpn)
1444b98478d71b0fea6d35f96069612d92b76013589fChristof Schmitt				port->d_id = 0;
1445c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			else {
1446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				port->wwnn = plogi->serv_param.wwnn;
1447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				zfcp_fc_plogi_evaluate(port, plogi);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_UNKNOWN_OP_SUBTYPE:
1452c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1457c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_port - create and send open port request
1459c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1462c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
146444cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1467c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
14690406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1470c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1471c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter,
1474c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  FSF_QTCB_OPEN_PORT_WITH_DID,
1475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1477025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1478c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1480c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1486c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_port_handler;
1487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.d_id = erp_action->port->d_id;
1488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1489c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1490c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1491c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1492287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1493c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
14990406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1505c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1507c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
150844cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1510c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
15125ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req);
1513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
15185ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_modify_port_status(port, "fscph_2", req,
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_STATUS_COMMON_OPEN,
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    ZFCP_CLEAR);
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1525c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_port - create and send close port request
1527c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1528c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1530c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
153244cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1533c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1534c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1535c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1536c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
15370406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
1539c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1540c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
1542c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1544025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1545c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1547c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1549c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1553c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_port_handler;
1554c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1555c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1556c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1557c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1558c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1559287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1560c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1562c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1565c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
15660406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15705ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligstatic void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
15715ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
15725ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_wka_port *wka_port = req->data;
15735ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
15745ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
15755ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
15765ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
15775ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
15785ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
15795ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
15805ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	switch (header->fsf_status) {
15815ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
15825ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		dev_warn(&req->adapter->ccw_device->dev,
15835ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig			 "Opening WKA port 0x%x failed\n", wka_port->d_id);
15845ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
15855ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
15865ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_ACCESS_DENIED:
15875ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->status = ZFCP_WKA_PORT_OFFLINE;
15885ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		break;
15895ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_PORT_ALREADY_OPEN:
15901c1cba17a9078c83a80a099bc207b208d664a13aChristof Schmitt		break;
15915ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	case FSF_GOOD:
15925ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->handle = header->port_handle;
15935ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		wka_port->status = ZFCP_WKA_PORT_ONLINE;
15945ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
15955ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligout:
15965ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	wake_up(&wka_port->completion_wq);
15975ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
15985ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
15995ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig/**
16005ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * zfcp_fsf_open_wka_port - create and send open wka-port request
16015ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * @wka_port: pointer to struct zfcp_wka_port
16025ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * Returns: 0 on success, error otherwise
16035ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig */
16045ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligint zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
16055ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
16065ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct qdio_buffer_element *sbale;
16075ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_adapter *adapter = wka_port->adapter;
16085ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_fsf_req *req;
16095ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	int retval = -EIO;
16105ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16110406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
16125ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
16135ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16145ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16155ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req = zfcp_fsf_req_create(adapter,
16165ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  FSF_QTCB_OPEN_PORT_WITH_DID,
16175ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
16185ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  adapter->pool.fsf_req_erp);
16195ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (unlikely(IS_ERR(req))) {
16205ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		retval = PTR_ERR(req);
16215ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16225ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
16235ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16245ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale = zfcp_qdio_sbale_req(req);
16255ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
16265ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
16275ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16285ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->handler = zfcp_fsf_open_wka_port_handler;
16295ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->qtcb->bottom.support.d_id = wka_port->d_id;
16305ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->data = wka_port;
16315ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16325ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
16335ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	retval = zfcp_fsf_req_send(req);
16345ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (retval)
16355ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		zfcp_fsf_req_free(req);
16365ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligout:
16370406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
16385ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	return retval;
16395ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
16405ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16415ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligstatic void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
16425ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
16435ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_wka_port *wka_port = req->data;
16445ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16455ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
16465ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
16475ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
16485ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
16495ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16505ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	wka_port->status = ZFCP_WKA_PORT_OFFLINE;
16515ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	wake_up(&wka_port->completion_wq);
16525ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
16535ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16545ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig/**
16555ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * zfcp_fsf_close_wka_port - create and send close wka port request
16565ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * @erp_action: pointer to struct zfcp_erp_action
16575ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig * Returns: 0 on success, error otherwise
16585ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig */
16595ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligint zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
16605ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig{
16615ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct qdio_buffer_element *sbale;
16625ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_adapter *adapter = wka_port->adapter;
16635ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	struct zfcp_fsf_req *req;
16645ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	int retval = -EIO;
16655ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16660406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
16675ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
16685ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16695ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16705ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
16715ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
16725ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig				  adapter->pool.fsf_req_erp);
16735ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (unlikely(IS_ERR(req))) {
16745ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		retval = PTR_ERR(req);
16755ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		goto out;
16765ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	}
16775ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16785ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale = zfcp_qdio_sbale_req(req);
16795ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
16805ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
16815ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16825ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->handler = zfcp_fsf_close_wka_port_handler;
16835ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->data = wka_port;
16845ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	req->qtcb->header.port_handle = wka_port->handle;
16855ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
16865ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
16875ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	retval = zfcp_fsf_req_send(req);
16885ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	if (retval)
16895ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig		zfcp_fsf_req_free(req);
16905ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schilligout:
16910406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
16925ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig	return retval;
16935ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig}
16945ab944f97e09a3d52951fe903eed9a7b88d810b2Swen Schillig
1695c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1697c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_port *port = req->data;
1698c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct zfcp_unit *unit;
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
1702a5b11dda12ed7e3a79180b10ad6209a40a02989fChristof Schmitt		return;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
17065ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req);
1707c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1710c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_port(req, port);
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
17135ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_boxed(port, "fscpph2", req);
1714c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1715c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
17165c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		/* can't use generic zfcp_erp_modify_port_status because
17175c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
17185c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
17195c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt		list_for_each_entry(unit, &port->unit_list_head, list)
17205c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
17215c815d1501a9ce84578cb3ec64c9d31ef91e3de2Christof Schmitt					  &unit->status);
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1726c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1728c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* can't use generic zfcp_erp_modify_port_status because
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(unit, &port->unit_list_head, list)
1738c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1739c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					  &unit->status);
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1744c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1745c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_physical_port - close physical port
1746c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1747c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1749c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
175144cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1752c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1753c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1754c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1755c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
17560406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1757c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1760c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT,
1761c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1762c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1763025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1764c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1765c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1766c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1768c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
1769c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1770c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1772c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->port;
1773c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1774c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1775c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_physical_port_handler;
1776c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1777c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1778287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1779c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1781c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1784c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
17850406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1789c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1791c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = req->adapter;
1792c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
1793c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
1794c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
1795c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_queue_designator *queue_designator =
1796c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				&header->fsf_status_qual.fsf_queue_designator;
1797aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin	int exclusive, readwrite;
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1799c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
180044cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1803b64ddf96456cde17be22bf74cafed381a29d58baHeiko Carstens			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_SHARED |
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ZFCP_STATUS_UNIT_READONLY,
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &unit->status);
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (header->fsf_status) {
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
18115ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req);
1812c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_ALREADY_OPEN:
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ACCESS_DENIED:
1816c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
1818553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
18215ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_boxed(unit->port, "fsouh_2", req);
1822c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1823c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_SHARING_VIOLATION:
1826c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0])
1827553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			dev_warn(&adapter->ccw_device->dev,
1828ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "LUN 0x%Lx on port 0x%Lx is already in "
1829ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 "use by CSS%d, MIF Image ID %x\n",
18307ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				 (unsigned long long)unit->fcp_lun,
18317ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				 (unsigned long long)unit->port->wwpn,
1832ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->cssid,
1833ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				 queue_designator->hla);
1834c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else
1835553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt			zfcp_act_eval_err(adapter,
1836553448f6c4838a1e4bed2bc9301c748278d7d9ceChristof Schmitt					  header->fsf_status_qual.word[2]);
18375ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_unit_access_denied(unit, "fsouh_3", req);
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
1840c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
1843c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_warn(&adapter->ccw_device->dev,
1844ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "No handle is available for LUN "
1845ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			 "0x%016Lx on port 0x%016Lx\n",
18467ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 (unsigned long long)unit->fcp_lun,
18477ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			 (unsigned long long)unit->port->wwpn);
18485ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_unit_failed(unit, "fsouh_4", req);
1849c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		/* fall through */
1850c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_INVALID_COMMAND_OPTION:
1851c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (header->fsf_status_qual.word[0]) {
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
185665a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1857c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1859c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unit->handle = header->lun_handle;
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
1867aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
1868aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
1869aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
1870aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin		    (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
1871aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			exclusive = (bottom->lun_access_info &
1872aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_EXCLUSIVE);
1873aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin			readwrite = (bottom->lun_access_info &
1874aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin					FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
1875aef4a983090fa590481a86d9690dc3fa6bb121faMaxim Shchetynin
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!exclusive)
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		                atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!readwrite) {
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                		atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&unit->status);
1883c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_info(&adapter->ccw_device->dev,
1884ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "SCSI device at LUN 0x%016Lx on port "
1885ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					 "0x%016Lx opened read-only\n",
18867ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					 (unsigned long long)unit->fcp_lun,
18877ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					 (unsigned long long)unit->port->wwpn);
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		if (exclusive && !readwrite) {
1891c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1892ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Exclusive read-only access not "
1893ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, "
1894ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"port 0x%016Lx)\n",
18957ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->fcp_lun,
18967ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->port->wwpn);
18975ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig				zfcp_erp_unit_failed(unit, "fsouh_5", req);
1898c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
18995ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req);
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		} else if (!exclusive && readwrite) {
1901c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				dev_err(&adapter->ccw_device->dev,
1902ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"Shared read-write access not "
1903ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt					"supported (unit 0x%016Lx, port "
190427c3f0a6e4521ba0ff6e76da54969f0bf430f53aChristof Schmitt					"0x%016Lx)\n",
19057ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->fcp_lun,
19067ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig					(unsigned long long)unit->port->wwpn);
19075ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig				zfcp_erp_unit_failed(unit, "fsouh_7", req);
1908c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19095ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig				zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req);
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        		}
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1916c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
1917c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_open_unit - open unit
1918c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_erp_action
1919c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1921c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
192344cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
1924c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
1925c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
1926c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
1927c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
19280406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
1929c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1932c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN,
1933c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
1934c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
1935025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
1936c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
1937c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
1938c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
1939c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1940c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1944c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
1945c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
1946c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_open_unit_handler;
1947c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
1948c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
1949c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
1950c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1951c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
1952c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
1953c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
1954287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
1955c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) {
1957c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		erp_action->fsf_req = NULL;
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1960c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
19610406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1965c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1967c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->data;
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1969c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
197044cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig		return;
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1972c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->header.fsf_status) {
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_HANDLE_NOT_VALID:
19745ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req);
1975c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_LUN_HANDLE_NOT_VALID:
19785ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req);
1979c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_PORT_BOXED:
19825ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_boxed(unit->port, "fscuh_3", req);
1983c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1984c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_ADAPTER_STATUS_AVAILABLE:
1987c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		switch (req->qtcb->header.fsf_status_qual.word[0]) {
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
198965a8d4e1a3754f0bfaa62949ebe919930e3127a1Andreas Herrmann			zfcp_test_link(unit->port);
1990c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			/* fall through */
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1992c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->status |= ZFCP_STATUS_FSFREQ_ERROR;
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FSF_GOOD:
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2003c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_close_unit - close zfcp unit
2004c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @erp_action: pointer to struct zfcp_unit
2005c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: 0 on success, error otherwise
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2007c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligint zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
200944cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2010c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_adapter *adapter = erp_action->adapter;
2011c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
2012c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int retval = -EIO;
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20140406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
2015c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2017c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
2018c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  ZFCP_REQ_AUTO_CLEANUP,
2019c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_erp);
2020025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2021c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
2022c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2023c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2025c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2026c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2029c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = erp_action->port->handle;
2030c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = erp_action->unit->handle;
2031c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_close_unit_handler;
2032c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = erp_action->unit;
2033c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->erp_action = erp_action;
2034c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	erp_action->fsf_req = req;
2035fdf234527a070f6fc89f3ec5ee4ae1b263e59939Christof Schmitt
2036287ac01acf22ab6aaaf9f5a4919ce2449c8b391cChristof Schmitt	zfcp_fsf_start_erp_timer(req);
2037c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2038c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (retval) {
2039c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
2040c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		erp_action->fsf_req = NULL;
2041c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2042c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
20430406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
2044c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2047c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmittstatic void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
2048c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
2049c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat_rec->sum += lat;
2050c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->min = min(lat_rec->min, lat);
2051c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_rec->max = max(lat_rec->max, lat);
2052c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt}
2053c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2054c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
2055c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt{
2056c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct fsf_qual_latency_info *lat_inf;
2057c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	struct latency_cont *lat;
2058c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit = req->unit;
2059c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2060c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
2061c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
2062c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (req->qtcb->bottom.io.data_direction) {
2063c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_READ:
2064c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.read;
2065c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
2066c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_WRITE:
2067c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.write;
2068c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
2069c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	case FSF_DATADIR_CMND:
2070c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		lat = &unit->latencies.cmd;
2071c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		break;
2072c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	default:
2073c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt		return;
2074c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	}
2075c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
207649f0f01c9966639f8fd7ce784a412e22057d9f2aChristof Schmitt	spin_lock(&unit->latencies.lock);
2077c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
2078c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
2079c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt	lat->counter++;
208049f0f01c9966639f8fd7ce784a412e22057d9f2aChristof Schmitt	spin_unlock(&unit->latencies.lock);
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20830997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#ifdef CONFIG_BLK_DEV_IO_TRACE
20840997f1c5fec0b540784611036d458a84a1f7029aStefan Rasplstatic void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
20850997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl{
20860997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct fsf_qual_latency_info *lat_inf;
20870997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
20880997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct request *req = scsi_cmnd->request;
20890997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	struct zfcp_blk_drv_data trace;
20900997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	int ticks = fsf_req->adapter->timer_ticks;
20910997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
20920997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.flags = 0;
20930997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.magic = ZFCP_BLK_DRV_DATA_MAGIC;
20940997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
20950997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.flags |= ZFCP_BLK_LAT_VALID;
20960997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
20970997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.channel_lat = lat_inf->channel_lat * ticks;
20980997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.fabric_lat = lat_inf->fabric_lat * ticks;
20990997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	}
21000997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
21010997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl		trace.flags |= ZFCP_BLK_REQ_ERROR;
21020997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.inb_usage = fsf_req->qdio_inb_usage;
21030997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	trace.outb_usage = fsf_req->qdio_outb_usage;
21040997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
21050997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	blk_add_driver_data(req->q, req, &trace, sizeof(trace));
21060997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl}
21070997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#else
21080997f1c5fec0b540784611036d458a84a1f7029aStefan Rasplstatic inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
21090997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl{
21100997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl}
21110997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl#endif
21120997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
2113c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21150ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig	struct scsi_cmnd *scpnt;
21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
2117c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sns_len;
2119f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2122c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_lock_irqsave(&req->adapter->abort_lock, flags);
2123c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
21240ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig	scpnt = req->data;
21250ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig	if (unlikely(!scpnt)) {
21260ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig		read_unlock_irqrestore(&req->adapter->abort_lock, flags);
21270ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig		return;
21280ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig	}
21290ac55aa90f2c3bd08e57e52a513b82b18ce0a5bcSwen Schillig
2130c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
2131feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_SOFT_ERROR);
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2135c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
2136feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann		set_host_byte(scpnt, DID_ERROR);
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2140feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann	set_msg_byte(scpnt, COMMAND_COMPLETE);
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->result |= fcp_rsp_iu->scsi_status;
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2144c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
2145c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_latency(req);
2146c9615858a81d2424c78b10a2f689ba24b156937cChristof Schmitt
21470997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl	zfcp_fsf_trace_latency(req);
21480997f1c5fec0b540784611036d458a84a1f7029aStefan Raspl
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
2150c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (fcp_rsp_info[3] == RSP_CODE_GOOD)
2151feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_OK);
2152c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2153feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
21546f71d9bc025b02a8cbc2be83b0226a7043a507a5<jejb@titanic.il.steeleye.com>			goto skip_fsfstatus;
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
2159c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
2160c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			  fcp_rsp_iu->fcp_rsp_len;
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21649d058ecfd444d247b7448e0ef44647514d91a4f2FUJITA Tomonori		memcpy(scpnt->sense_buffer,
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
21697936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
21707936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
21717936a892e72498a05b9a7fb1fec6506d65c8e435FUJITA Tomonori		    scpnt->underflow)
2172feac6a07c4a3578bffd6769bb4927e8a7e1f3ffeMartin Petermann			set_host_byte(scpnt, DID_ERROR);
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2174c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
21758a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	if (scpnt->result != 0)
2176c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req);
21778a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else if (scpnt->retries > 0)
2178c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req);
21798a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin	else
2180c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req);
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scpnt->host_scribble = NULL;
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(scpnt->scsi_done) (scpnt);
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We must hold this lock until scsi_done has been called.
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we may call scsi_done after abort regarding this
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * command has completed.
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Note: scsi_done must not block!
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2190c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	read_unlock_irqrestore(&req->adapter->abort_lock, flags);
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2193c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
2196c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	    &(req->qtcb->bottom.io.fcp_rsp);
2197f76af7d7e36373179be7a9e09f6b0aae330549b7Martin Petermann	char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2199c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
2200c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	     (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2201c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
2202c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
2203c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2204c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2205c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
2206c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2207c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_unit *unit;
2208c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_header *header = &req->qtcb->header;
2209c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2210c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
2211c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->data;
2212c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2213c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		unit = req->unit;
2214c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2215c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto skip_fsfstatus;
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2218c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (header->fsf_status) {
2219c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_HANDLE_MISMATCH:
2220c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_HANDLE_NOT_VALID:
22215ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", req);
2222c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2223c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2224c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_FCPLUN_NOT_VALID:
2225c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_HANDLE_NOT_VALID:
22265ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_reopen(unit->port, 0, "fssfch2", req);
2227c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2229c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2230c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_class_not_supp(req);
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2232c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ACCESS_DENIED:
2233c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_access_denied_unit(req, unit);
2234c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2235c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_DIRECTION_INDICATOR_NOT_VALID:
2236c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2237ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect direction %d, unit 0x%016Lx on port "
2238ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"0x%016Lx closed\n",
2239c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.data_direction,
22407ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->fcp_lun,
22417ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->port->wwpn);
22425ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3",
22435ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig					  req);
2244c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2245c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2246c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_CMND_LENGTH_NOT_VALID:
2247c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		dev_err(&req->adapter->ccw_device->dev,
2248ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"Incorrect CDB length %d, unit 0x%016Lx on "
2249ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt			"port 0x%016Lx closed\n",
2250c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			req->qtcb->bottom.io.fcp_cmnd_length,
22517ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->fcp_lun,
22527ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(unsigned long long)unit->port->wwpn);
22535ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4",
22545ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig					  req);
2255c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2256c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2257c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_PORT_BOXED:
22585ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_port_boxed(unit->port, "fssfch5", req);
2259c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2260c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2261c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2262c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_LUN_BOXED:
22635ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig		zfcp_erp_unit_boxed(unit, "fssfch6", req);
2264c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2265c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			       ZFCP_STATUS_FSFREQ_RETRY;
2266c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2267c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_ADAPTER_STATUS_AVAILABLE:
2268c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (header->fsf_status_qual.word[0] ==
2269c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
2270c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			zfcp_test_link(unit->port);
2271c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2274c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligskip_fsfstatus:
2275c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
2276c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_ctm_handler(req);
2277c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else {
2278c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_send_fcp_command_task_handler(req);
2279c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->unit = NULL;
2280c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_unit_put(unit);
2281c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22847ba58c9cc16d296290fe645acb11db2b01276544Swen Schilligstatic void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
22857ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig{
22867ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	u32 *fcp_dl_ptr;
22877ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig
22887ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	/*
22897ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 * fcp_dl_addr = start address of fcp_cmnd structure +
22907ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 * size of fixed part + size of dynamically sized add_dcp_cdb field
22917ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 * SEE FCP-2 documentation
22927ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	 */
22937ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
22947ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig			(fcp_cmd->add_fcp_cdb_length << 2));
22957ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig	*fcp_dl_ptr = fcp_dl;
22967ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig}
22977ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig
2298c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2299c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
2300c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: unit where command is sent to
2301c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @scsi_cmnd: scsi command to be sent
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
230363caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmittint zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
230463caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt				   struct scsi_cmnd *scsi_cmnd)
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2306c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req;
2307c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
2308c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	unsigned int sbtype;
2309c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int real_bytes, retval = -EIO;
231063caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt	struct zfcp_adapter *adapter = unit->port->adapter;
23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2312c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2313c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2314c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return -EBUSY;
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23160406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock(&adapter->req_q_lock);
23178fdf30d5429605a4c30cc515c73e5eab140035deChristof Schmitt	if (atomic_read(&adapter->req_q.count) <= 0) {
23188fdf30d5429605a4c30cc515c73e5eab140035deChristof Schmitt		atomic_inc(&adapter->qdio_outb_full);
2319c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
23208fdf30d5429605a4c30cc515c73e5eab140035deChristof Schmitt	}
232163caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND,
232263caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt				  ZFCP_REQ_AUTO_CLEANUP,
2323c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2324025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2325c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = PTR_ERR(req);
2326c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2327c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
2328c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2329c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_get(unit);
2330c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->unit = unit;
2331c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = scsi_cmnd;
2332c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2333c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2334c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2335c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2336c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2337c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2338c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2339c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
2340c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2341c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	/*
2342c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 * set depending on data direction:
2343c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in SBALE (SB Type)
2344c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in QTCB
2345c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 *      data direction bits in FCP_CMND IU
2346c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	 */
2347c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (scsi_cmnd->sc_data_direction) {
2348c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_NONE:
2349c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2350c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2352c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_FROM_DEVICE:
2353c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2354c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_READ;
2355c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->rddata = 1;
2356c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2357c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_TO_DEVICE:
2358c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2359c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		sbtype = SBAL_FLAGS0_TYPE_WRITE;
2360c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->wddata = 1;
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2362c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case DMA_BIDIRECTIONAL:
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2364c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EIO;
2365c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2368c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (likely((scsi_cmnd->device->simple_tags) ||
2369c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		   ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
2370c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		    (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
2371c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = SIMPLE_Q;
2372c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	else
2373c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->task_attribute = UNTAGGED;
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2375c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
2376c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		fcp_cmnd_iu->add_fcp_cdb_length =
2377c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			(scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2379c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
238045633fdc9615f9fd2a0ae18e301562298b15abf3Christof Schmitt
2381c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
23827ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig		fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2384c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
2385c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     scsi_sglist(scsi_cmnd),
2386c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					     FSF_MAX_SBALS_PER_REQ);
2387c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(real_bytes < 0)) {
2388c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
2389c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EIO;
2390c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		else {
2391c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			dev_err(&adapter->ccw_device->dev,
2392ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"Oversize data package, unit 0x%016Lx "
2393ff3b24fa5370a7ca618f212284d9b36fcedb9c0eChristof Schmitt				"on port 0x%016Lx closed\n",
23947ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				(unsigned long long)unit->fcp_lun,
23957ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig				(unsigned long long)unit->port->wwpn);
23965ffd51a5e495a2a002efd523aef0001912b080bdSwen Schillig			zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
2397c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			retval = -EINVAL;
2398c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		}
2399c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2402c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2404c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2405c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(retval))
2406c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto failed_scsi_cmnd;
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2408c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	goto out;
24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2410c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligfailed_scsi_cmnd:
2411c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_unit_put(unit);
2412c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2413c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	scsi_cmnd->host_scribble = NULL;
2414c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
24150406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock(&adapter->req_q_lock);
2416c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return retval;
24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2420c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_send_fcp_ctm - send SCSI task management command
2421c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @unit: pointer to struct zfcp_unit
2422c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @tm_flags: unsigned byte for task management flags
2423c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct fsf_req, NULL otherwise
24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
242563caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmittstruct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
242744cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2428c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2429c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fcp_cmnd_iu *fcp_cmnd_iu;
243063caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt	struct zfcp_adapter *adapter = unit->port->adapter;
24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2432c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (unlikely(!(atomic_read(&unit->status) &
2433c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		       ZFCP_STATUS_COMMON_UNBLOCKED)))
2434c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return NULL;
24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243692cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
243792cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	if (zfcp_fsf_req_sbal_get(adapter))
2438c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
243963caf367e1c92e0667a344d9b687c04e6ef054b5Christof Schmitt	req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0,
2440c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig				  adapter->pool.fsf_req_scsi);
2441633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	if (IS_ERR(req)) {
2442633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig		req = NULL;
2443c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2444633528c304f20b5c2e3e04d48f620548ce08b12eSwen Schillig	}
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2446c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2447c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->data = unit;
2448c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_send_fcp_command_handler;
2449c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.lun_handle = unit->handle;
2450c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->header.port_handle = unit->port->handle;
2451c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2452c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2453c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->qtcb->bottom.io.fcp_cmnd_length = 	sizeof(struct fcp_cmnd_iu) +
24547ba58c9cc16d296290fe645acb11db2b01276544Swen Schillig						sizeof(u32);
2455c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2456c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2457c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2458c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2460c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
2461c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2462c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	fcp_cmnd_iu->task_management_flags = tm_flags;
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2464c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2465c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!zfcp_fsf_req_send(req))
2466c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2468c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_req_free(req);
2469c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = NULL;
2470c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
247192cab0d93a1107ad7f6d827fde62d1aa4db15e86Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
2472c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return req;
2473c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig}
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2475c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstatic void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
2476c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig{
2477c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (req->qtcb->header.fsf_status != FSF_GOOD)
2478c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		req->status |= ZFCP_STATUS_FSFREQ_ERROR;
24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig/**
2482c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * zfcp_fsf_control_file - control file upload/download
2483c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @adapter: pointer to struct zfcp_adapter
2484c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc
2485c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2487c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligstruct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2488c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					   struct zfcp_fsf_cfdc *fsf_cfdc)
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
249044cc76f2d154aa24340354b4711a0fe7f8f08adcSwen Schillig	struct qdio_buffer_element *sbale;
2491c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct zfcp_fsf_req *req = NULL;
2492c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	struct fsf_qtcb_bottom_support *bottom;
2493c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	int direction, retval = -EIO, bytes;
2494c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2495c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
2496c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EOPNOTSUPP);
2497c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig
2498c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	switch (fsf_cfdc->command) {
2499c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
2500c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_WRITE;
2501c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2502c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	case FSF_QTCB_UPLOAD_CONTROL_FILE:
2503c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		direction = SBAL_FLAGS0_TYPE_READ;
2504c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		break;
2505c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	default:
2506c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return ERR_PTR(-EINVAL);
2507c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25090406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_lock_bh(&adapter->req_q_lock);
2510c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (zfcp_fsf_req_sbal_get(adapter))
2511c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2513c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL);
2514025270f0eaa2def673747ed6f77cca41f694f354Hirofumi Nakagawa	if (IS_ERR(req)) {
2515c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -EPERM;
2516c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2517c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2519c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	req->handler = zfcp_fsf_control_file_handler;
25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale = zfcp_qdio_sbale_req(req);
2522c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	sbale[0].flags |= direction;
25238a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2524c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom = &req->qtcb->bottom.support;
2525c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
2526c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bottom->option = fsf_cfdc->option;
25278a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2528c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
2529c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig					FSF_MAX_SBALS_PER_REQ);
2530c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (bytes != ZFCP_CFDC_MAX_SIZE) {
2531c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		retval = -ENOMEM;
2532c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		zfcp_fsf_req_free(req);
2533c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		goto out;
2534c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	}
25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2536c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2537c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	retval = zfcp_fsf_req_send(req);
2538c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schilligout:
25390406289ed57955860a4f8d744a14f4c819260ce4Christof Schmitt	spin_unlock_bh(&adapter->req_q_lock);
25408a36e4532ea10471f0a8605207d071361d7be2c3Maxim Shchetynin
2541c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	if (!retval) {
2542c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		wait_event(req->completion_wq,
2543c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig			   req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
2544c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig		return req;
25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2546c41f8cbddd4e0e72951e0575165dea8ea26f1c4bSwen Schillig	return ERR_PTR(retval);
25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2548