blob: b4c9ba085093f78655da266abe0015258de16c6a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Christof Schmitt553448f2008-06-10 18:20:58 +02002 * zfcp device driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Christof Schmitt553448f2008-06-10 18:20:58 +02004 * Implementation of FSF commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Christof Schmitt553448f2008-06-10 18:20:58 +02006 * Copyright IBM Corporation 2002, 2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Christof Schmittecf39d42008-12-25 13:39:53 +01009#define KMSG_COMPONENT "zfcp"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
Stefan Raspl0997f1c2008-10-16 08:23:39 +020012#include <linux/blktrace_api.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "zfcp_ext.h"
14
Christof Schmitt63caf362009-03-02 13:09:00 +010015#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
16#define ZFCP_REQ_NO_QTCB 0x00000008
17
Christof Schmitt287ac012008-07-02 10:56:40 +020018static void zfcp_fsf_request_timeout_handler(unsigned long data)
19{
20 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
Swen Schillig5ffd51a2009-03-02 13:09:04 +010021 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
22 "fsrth_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +020023}
24
25static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req,
26 unsigned long timeout)
27{
28 fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
29 fsf_req->timer.data = (unsigned long) fsf_req->adapter;
30 fsf_req->timer.expires = jiffies + timeout;
31 add_timer(&fsf_req->timer);
32}
33
34static void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req)
35{
36 BUG_ON(!fsf_req->erp_action);
37 fsf_req->timer.function = zfcp_erp_timeout_handler;
38 fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
39 fsf_req->timer.expires = jiffies + 30 * HZ;
40 add_timer(&fsf_req->timer);
41}
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043/* association between FSF command and FSF QTCB type */
44static u32 fsf_qtcb_type[] = {
45 [FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND,
46 [FSF_QTCB_ABORT_FCP_CMND] = FSF_SUPPORT_COMMAND,
47 [FSF_QTCB_OPEN_PORT_WITH_DID] = FSF_SUPPORT_COMMAND,
48 [FSF_QTCB_OPEN_LUN] = FSF_SUPPORT_COMMAND,
49 [FSF_QTCB_CLOSE_LUN] = FSF_SUPPORT_COMMAND,
50 [FSF_QTCB_CLOSE_PORT] = FSF_SUPPORT_COMMAND,
51 [FSF_QTCB_CLOSE_PHYSICAL_PORT] = FSF_SUPPORT_COMMAND,
52 [FSF_QTCB_SEND_ELS] = FSF_SUPPORT_COMMAND,
53 [FSF_QTCB_SEND_GENERIC] = FSF_SUPPORT_COMMAND,
54 [FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
55 [FSF_QTCB_EXCHANGE_PORT_DATA] = FSF_PORT_COMMAND,
56 [FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
57 [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
58};
59
Christof Schmitt553448f2008-06-10 18:20:58 +020060static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
61{
Swen Schilligc41f8cb2008-07-02 10:56:39 +020062 u16 subtable = table >> 16;
Christof Schmitt553448f2008-06-10 18:20:58 +020063 u16 rule = table & 0xffff;
Christof Schmittff3b24f2008-10-01 12:42:15 +020064 const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
Christof Schmitt553448f2008-06-10 18:20:58 +020065
Christof Schmittff3b24f2008-10-01 12:42:15 +020066 if (subtable && subtable < ARRAY_SIZE(act_type))
Christof Schmitt553448f2008-06-10 18:20:58 +020067 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +020068 "Access denied according to ACT rule type %s, "
69 "rule %d\n", act_type[subtable], rule);
Christof Schmitt553448f2008-06-10 18:20:58 +020070}
71
72static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
73 struct zfcp_port *port)
74{
75 struct fsf_qtcb_header *header = &req->qtcb->header;
76 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +020077 "Access denied to port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +020078 (unsigned long long)port->wwpn);
Christof Schmitt553448f2008-06-10 18:20:58 +020079 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
80 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +010081 zfcp_erp_port_access_denied(port, "fspad_1", req);
Christof Schmitt553448f2008-06-10 18:20:58 +020082 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
83}
84
85static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
86 struct zfcp_unit *unit)
87{
88 struct fsf_qtcb_header *header = &req->qtcb->header;
89 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +020090 "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +020091 (unsigned long long)unit->fcp_lun,
92 (unsigned long long)unit->port->wwpn);
Christof Schmitt553448f2008-06-10 18:20:58 +020093 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
94 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +010095 zfcp_erp_unit_access_denied(unit, "fsuad_1", req);
Christof Schmitt553448f2008-06-10 18:20:58 +020096 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
97}
98
99static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
100{
Christof Schmittff3b24f2008-10-01 12:42:15 +0200101 dev_err(&req->adapter->ccw_device->dev, "FCP device not "
102 "operational because of an unsupported FC class\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100103 zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req);
Christof Schmitt553448f2008-06-10 18:20:58 +0200104 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
105}
106
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200107/**
108 * zfcp_fsf_req_free - free memory used by fsf request
109 * @fsf_req: pointer to struct zfcp_fsf_req
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200111void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200113 if (likely(req->pool)) {
114 mempool_free(req, req->pool);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200115 return;
116 }
117
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200118 if (req->qtcb) {
119 kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200120 return;
121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200124/**
125 * zfcp_fsf_req_dismiss_all - dismiss all fsf requests
126 * @adapter: pointer to struct zfcp_adapter
127 *
Martin Peschke869b2b42007-05-09 11:01:20 +0200128 * Never ever call this without shutting down the adapter first.
129 * Otherwise the adapter would continue using and corrupting s390 storage.
130 * Included BUG_ON() call to ensure this is done.
131 * ERP is supposed to be the only user of this function.
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200132 */
Swen Schillig6fcc4712007-02-07 13:17:57 +0100133void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200134{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200135 struct zfcp_fsf_req *req, *tmp;
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200136 unsigned long flags;
Swen Schillig6fcc4712007-02-07 13:17:57 +0100137 LIST_HEAD(remove_queue);
Martin Peschke869b2b42007-05-09 11:01:20 +0200138 unsigned int i;
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200139
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200140 BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP);
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200141 spin_lock_irqsave(&adapter->req_list_lock, flags);
Martin Peschke869b2b42007-05-09 11:01:20 +0200142 for (i = 0; i < REQUEST_LIST_SIZE; i++)
Swen Schillig6fcc4712007-02-07 13:17:57 +0100143 list_splice_init(&adapter->req_list[i], &remove_queue);
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200144 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
145
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200146 list_for_each_entry_safe(req, tmp, &remove_queue, list) {
147 list_del(&req->list);
148 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
149 zfcp_fsf_req_complete(req);
Swen Schillig6fcc4712007-02-07 13:17:57 +0100150 }
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200151}
152
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200153static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200155 struct fsf_status_read_buffer *sr_buf = req->data;
156 struct zfcp_adapter *adapter = req->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 struct zfcp_port *port;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200158 int d_id = sr_buf->d_id & ZFCP_DID_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 unsigned long flags;
160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 read_lock_irqsave(&zfcp_data.config_lock, flags);
162 list_for_each_entry(port, &adapter->port_list_head, list)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200163 if (port->d_id == d_id) {
164 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100165 zfcp_erp_port_reopen(port, 0, "fssrpc1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200166 return;
167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169}
170
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100171static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200172 struct fsf_link_down_info *link_down)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200174 struct zfcp_adapter *adapter = req->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200176 if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)
177 return;
178
179 atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
180
181 if (!link_down)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 goto out;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200183
184 switch (link_down->error_code) {
185 case FSF_PSQ_LINK_NO_LIGHT:
186 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200187 "There is no light signal from the local "
188 "fibre channel cable\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200189 break;
190 case FSF_PSQ_LINK_WRAP_PLUG:
191 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200192 "There is a wrap plug instead of a fibre "
193 "channel cable\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200194 break;
195 case FSF_PSQ_LINK_NO_FCP:
196 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200197 "The adjacent fibre channel node does not "
198 "support FCP\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200199 break;
200 case FSF_PSQ_LINK_FIRMWARE_UPDATE:
201 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200202 "The FCP device is suspended because of a "
203 "firmware update\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200204 break;
205 case FSF_PSQ_LINK_INVALID_WWPN:
206 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200207 "The FCP device detected a WWPN that is "
208 "duplicate or not valid\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200209 break;
210 case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
211 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200212 "The fibre channel fabric does not support NPIV\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200213 break;
214 case FSF_PSQ_LINK_NO_FCP_RESOURCES:
215 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200216 "The FCP adapter cannot support more NPIV ports\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200217 break;
218 case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
219 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200220 "The adjacent switch cannot support "
221 "more NPIV ports\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200222 break;
223 case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
224 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200225 "The FCP adapter could not log in to the "
226 "fibre channel fabric\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200227 break;
228 case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
229 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200230 "The WWPN assignment file on the FCP adapter "
231 "has been damaged\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200232 break;
233 case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
234 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200235 "The mode table on the FCP adapter "
236 "has been damaged\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200237 break;
238 case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
239 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200240 "All NPIV ports on the FCP adapter have "
241 "been assigned\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200242 break;
243 default:
244 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200245 "The link between the FCP adapter and "
246 "the FC fabric is down\n");
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200247 }
248out:
249 zfcp_erp_adapter_failed(adapter, id, req);
250}
251
252static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
253{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200254 struct fsf_status_read_buffer *sr_buf = req->data;
255 struct fsf_link_down_info *ldi =
256 (struct fsf_link_down_info *) &sr_buf->payload;
257
258 switch (sr_buf->status_subtype) {
259 case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100260 zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200261 break;
262 case FSF_STATUS_READ_SUB_FDISC_FAILED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100263 zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200264 break;
265 case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100266 zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200267 };
268}
269
270static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
271{
272 struct zfcp_adapter *adapter = req->adapter;
273 struct fsf_status_read_buffer *sr_buf = req->data;
274
275 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
276 zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf);
277 mempool_free(sr_buf, adapter->pool.data_status_read);
278 zfcp_fsf_req_free(req);
279 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 }
281
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200282 zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200283
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200284 switch (sr_buf->status_type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 case FSF_STATUS_READ_PORT_CLOSED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200286 zfcp_fsf_status_read_port_closed(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 case FSF_STATUS_READ_INCOMING_ELS:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200289 zfcp_fc_incoming_els(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 case FSF_STATUS_READ_SENSE_DATA_AVAIL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
Christof Schmittff3b24f2008-10-01 12:42:15 +0200294 dev_warn(&adapter->ccw_device->dev,
295 "The error threshold for checksum statistics "
296 "has been exceeded\n");
Swen Schillig57069382008-10-01 12:42:21 +0200297 zfcp_hba_dbf_event_berr(adapter, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 case FSF_STATUS_READ_LINK_DOWN:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200300 zfcp_fsf_status_read_link_down(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 case FSF_STATUS_READ_LINK_UP:
Christof Schmitt553448f2008-06-10 18:20:58 +0200303 dev_info(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200304 "The local link has been restored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 /* All ports should be marked as ready to run again */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100306 zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 ZFCP_STATUS_COMMON_RUNNING,
308 ZFCP_SET);
309 zfcp_erp_adapter_reopen(adapter,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200310 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
311 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100312 "fssrh_2", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 break;
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100314 case FSF_STATUS_READ_NOTIFICATION_LOST:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200315 if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100316 zfcp_erp_adapter_access_changed(adapter, "fssrh_3",
317 req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200318 if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
Swen Schilligcc8c2822008-06-10 18:21:00 +0200319 schedule_work(&adapter->scan_work);
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100320 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 case FSF_STATUS_READ_CFDC_UPDATED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100322 zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200324 case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200325 adapter->adapter_features = sr_buf->payload.word[0];
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200326 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200328
329 mempool_free(sr_buf, adapter->pool.data_status_read);
330 zfcp_fsf_req_free(req);
Swen Schilligd26ab062008-05-19 12:17:37 +0200331
332 atomic_inc(&adapter->stat_miss);
Swen Schilligb7f15f32008-10-01 12:42:22 +0200333 queue_work(zfcp_data.work_queue, &adapter->stat_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200336static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200338 switch (req->qtcb->header.fsf_status_qual.word[0]) {
339 case FSF_SQ_FCP_RSP_AVAILABLE:
340 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
341 case FSF_SQ_NO_RETRY_POSSIBLE:
342 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
343 return;
344 case FSF_SQ_COMMAND_ABORTED:
345 req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
346 break;
347 case FSF_SQ_NO_RECOM:
348 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200349 "The FCP adapter reported a problem "
350 "that cannot be recovered\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100351 zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200352 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200354 /* all non-return stats set FSFREQ_ERROR*/
355 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
356}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200358static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
359{
360 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
361 return;
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200362
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200363 switch (req->qtcb->header.fsf_status) {
364 case FSF_UNKNOWN_COMMAND:
365 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200366 "The FCP adapter does not recognize the command 0x%x\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200367 req->qtcb->header.fsf_command);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100368 zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200369 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 case FSF_ADAPTER_STATUS_AVAILABLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200372 zfcp_fsf_fsfstatus_qual_eval(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200377static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200379 struct zfcp_adapter *adapter = req->adapter;
380 struct fsf_qtcb *qtcb = req->qtcb;
381 union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200383 zfcp_hba_dbf_event_fsf_response(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200385 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
386 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
387 ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
388 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 }
390
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200391 switch (qtcb->prefix.prot_status) {
392 case FSF_PROT_GOOD:
393 case FSF_PROT_FSF_STATUS_PRESENTED:
394 return;
395 case FSF_PROT_QTCB_VERSION_ERROR:
396 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200397 "QTCB version 0x%x not supported by FCP adapter "
398 "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
399 psq->word[0], psq->word[1]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100400 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200402 case FSF_PROT_ERROR_STATE:
403 case FSF_PROT_SEQ_NUMB_ERROR:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100404 zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200405 req->status |= ZFCP_STATUS_FSFREQ_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200407 case FSF_PROT_UNSUPP_QTCB_TYPE:
408 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200409 "The QTCB type is not supported by the FCP adapter\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100410 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200412 case FSF_PROT_HOST_CONNECTION_INITIALIZING:
413 atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
414 &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200416 case FSF_PROT_DUPLICATE_REQUEST_ID:
417 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200418 "0x%Lx is an ambiguous request identifier\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200419 (unsigned long long)qtcb->bottom.support.req_handle);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100420 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200422 case FSF_PROT_LINK_DOWN:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100423 zfcp_fsf_link_down_info_eval(req, "fspse_5",
424 &psq->link_down_info);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200425 /* FIXME: reopening adapter now? better wait for link up */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100426 zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200428 case FSF_PROT_REEST_QUEUE:
429 /* All ports should be marked as ready to run again */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100430 zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL,
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200431 ZFCP_STATUS_COMMON_RUNNING,
432 ZFCP_SET);
433 zfcp_erp_adapter_reopen(adapter,
434 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100435 ZFCP_STATUS_COMMON_ERP_FAILED,
436 "fspse_8", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200437 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 default:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200439 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200440 "0x%x is not a valid transfer protocol status\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200441 qtcb->prefix.prot_status);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100442 zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200444 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
447/**
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200448 * zfcp_fsf_req_complete - process completion of a FSF request
449 * @fsf_req: The FSF request that has been completed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 *
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200451 * When a request has been completed either from the FCP adapter,
452 * or it has been dismissed due to a queue shutdown, this function
453 * is called to process the completion status and trigger further
454 * events related to the FSF request.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200456void zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
457{
458 if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
459 zfcp_fsf_status_read_handler(req);
460 return;
461 }
462
463 del_timer(&req->timer);
464 zfcp_fsf_protstatus_eval(req);
465 zfcp_fsf_fsfstatus_eval(req);
466 req->handler(req);
467
468 if (req->erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200469 zfcp_erp_notify(req->erp_action, 0);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200470 req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
471
472 if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
473 zfcp_fsf_req_free(req);
474 else
475 /* notify initiator waiting for the requests completion */
476 /*
477 * FIXME: Race! We must not access fsf_req here as it might have been
478 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
479 * flag. It's an improbable case. But, we have the same paranoia for
480 * the cleanup flag already.
481 * Might better be handled using complete()?
482 * (setting the flag and doing wakeup ought to be atomic
483 * with regard to checking the flag as long as waitqueue is
484 * part of the to be released structure)
485 */
486 wake_up(&req->completion_wq);
487}
488
489static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
491 struct fsf_qtcb_bottom_config *bottom;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200492 struct zfcp_adapter *adapter = req->adapter;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200493 struct Scsi_Host *shost = adapter->scsi_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200495 bottom = &req->qtcb->bottom.config;
496
497 if (req->data)
498 memcpy(req->data, bottom, sizeof(*bottom));
499
500 fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
501 fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
502 fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
503 fc_host_speed(shost) = bottom->fc_link_speed;
504 fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
505
506 adapter->hydra_version = bottom->adapter_type;
507 adapter->timer_ticks = bottom->timer_interval;
508
509 if (fc_host_permanent_port_name(shost) == -1)
510 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
511
512 switch (bottom->fc_topology) {
513 case FSF_TOPO_P2P:
514 adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
515 adapter->peer_wwpn = bottom->plogi_payload.wwpn;
516 adapter->peer_wwnn = bottom->plogi_payload.wwnn;
517 fc_host_port_type(shost) = FC_PORTTYPE_PTP;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200518 break;
519 case FSF_TOPO_FABRIC:
520 fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200521 break;
522 case FSF_TOPO_AL:
523 fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200524 default:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200525 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200526 "Unknown or unsupported arbitrated loop "
527 "fibre channel topology detected\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100528 zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200529 return -EIO;
530 }
531
532 return 0;
533}
534
535static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
536{
537 struct zfcp_adapter *adapter = req->adapter;
538 struct fsf_qtcb *qtcb = req->qtcb;
539 struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config;
540 struct Scsi_Host *shost = adapter->scsi_host;
541
542 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
543 return;
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 adapter->fsf_lic_version = bottom->lic_version;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200546 adapter->adapter_features = bottom->adapter_features;
547 adapter->connection_features = bottom->connection_features;
6f71d9b2005-04-10 23:04:28 -0500548 adapter->peer_wwpn = 0;
549 adapter->peer_wwnn = 0;
550 adapter->peer_d_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200552 switch (qtcb->header.fsf_status) {
553 case FSF_GOOD:
554 if (zfcp_fsf_exchange_config_evaluate(req))
555 return;
Swen Schillig52ef11a2007-08-28 09:31:09 +0200556
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200557 if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
558 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200559 "FCP adapter maximum QTCB size (%d bytes) "
560 "is too small\n",
561 bottom->max_qtcb_size);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100562 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200563 return;
564 }
565 atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
566 &adapter->status);
567 break;
568 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200569 fc_host_node_name(shost) = 0;
570 fc_host_port_name(shost) = 0;
571 fc_host_port_id(shost) = 0;
572 fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
Andreas Herrmannad757cd2006-01-13 02:26:11 +0100573 fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 adapter->hydra_version = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200575
576 atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
577 &adapter->status);
578
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100579 zfcp_fsf_link_down_info_eval(req, "fsecdh2",
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200580 &qtcb->header.fsf_status_qual.link_down_info);
581 break;
582 default:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100583 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200584 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
586
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200587 if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 adapter->hardware_version = bottom->hardware_version;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +0200589 memcpy(fc_host_serial_number(shost), bottom->serial_number,
590 min(FC_SERIAL_NUMBER_SIZE, 17));
591 EBCASC(fc_host_serial_number(shost),
592 min(FC_SERIAL_NUMBER_SIZE, 17));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
594
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200595 if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +0200596 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200597 "The FCP adapter only supports newer "
598 "control block versions\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100599 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200600 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200602 if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +0200603 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +0200604 "The FCP adapter only supports older "
605 "control block versions\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100606 zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608}
609
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200610static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200612 struct zfcp_adapter *adapter = req->adapter;
613 struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port;
614 struct Scsi_Host *shost = adapter->scsi_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200616 if (req->data)
617 memcpy(req->data, bottom, sizeof(*bottom));
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100618
619 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
620 fc_host_permanent_port_name(shost) = bottom->wwpn;
621 else
622 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
623 fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
624 fc_host_supported_speeds(shost) = bottom->supported_speed;
625}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200627static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200629 struct fsf_qtcb *qtcb = req->qtcb;
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100630
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200631 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return;
633
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200634 switch (qtcb->header.fsf_status) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200635 case FSF_GOOD:
636 zfcp_fsf_exchange_port_evaluate(req);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200637 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200638 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200639 zfcp_fsf_exchange_port_evaluate(req);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100640 zfcp_fsf_link_down_info_eval(req, "fsepdh1",
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200641 &qtcb->header.fsf_status_qual.link_down_info);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200642 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644}
645
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200646static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
Christof Schmittdedbc2b2008-12-19 16:56:54 +0100647 __releases(&adapter->req_q_lock)
648 __acquires(&adapter->req_q_lock)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200649{
Christof Schmittdedbc2b2008-12-19 16:56:54 +0100650 struct zfcp_qdio_queue *req_q = &adapter->req_q;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200651 long ret;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200652
Christof Schmittdedbc2b2008-12-19 16:56:54 +0100653 if (atomic_read(&req_q->count) <= -REQUEST_LIST_SIZE)
654 return -EIO;
655 if (atomic_read(&req_q->count) > 0)
656 return 0;
657
658 atomic_dec(&req_q->count);
Christof Schmitt04062892008-10-01 12:42:20 +0200659 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200660 ret = wait_event_interruptible_timeout(adapter->request_wq,
Christof Schmittdedbc2b2008-12-19 16:56:54 +0100661 atomic_read(&req_q->count) >= 0,
662 5 * HZ);
663 spin_lock_bh(&adapter->req_q_lock);
664 atomic_inc(&req_q->count);
665
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200666 if (ret > 0)
667 return 0;
Stefan Raspl2450d3e2008-10-01 12:42:14 +0200668 if (!ret)
669 atomic_inc(&adapter->qdio_outb_full);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200670 return -EIO;
671}
672
673static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool)
674{
675 struct zfcp_fsf_req *req;
676 req = mempool_alloc(pool, GFP_ATOMIC);
677 if (!req)
678 return NULL;
679 memset(req, 0, sizeof(*req));
Christof Schmitt88f2a972008-11-04 16:35:07 +0100680 req->pool = pool;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200681 return req;
682}
683
684static struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool)
685{
686 struct zfcp_fsf_req_qtcb *qtcb;
687
688 if (likely(pool))
689 qtcb = mempool_alloc(pool, GFP_ATOMIC);
690 else
691 qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
692 GFP_ATOMIC);
693 if (unlikely(!qtcb))
694 return NULL;
695
696 memset(qtcb, 0, sizeof(*qtcb));
697 qtcb->fsf_req.qtcb = &qtcb->qtcb;
698 qtcb->fsf_req.pool = pool;
699
700 return &qtcb->fsf_req;
701}
702
703static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
704 u32 fsf_cmd, int req_flags,
705 mempool_t *pool)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200707 struct qdio_buffer_element *sbale;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200709 struct zfcp_fsf_req *req;
710 struct zfcp_qdio_queue *req_q = &adapter->req_q;
711
712 if (req_flags & ZFCP_REQ_NO_QTCB)
713 req = zfcp_fsf_alloc_noqtcb(pool);
714 else
715 req = zfcp_fsf_alloc_qtcb(pool);
716
717 if (unlikely(!req))
718 return ERR_PTR(-EIO);
719
720 if (adapter->req_no == 0)
721 adapter->req_no++;
722
723 INIT_LIST_HEAD(&req->list);
724 init_timer(&req->timer);
725 init_waitqueue_head(&req->completion_wq);
726
727 req->adapter = adapter;
728 req->fsf_command = fsf_cmd;
Christof Schmitt52bfb552009-03-02 13:08:58 +0100729 req->req_id = adapter->req_no;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200730 req->sbal_number = 1;
731 req->sbal_first = req_q->first;
732 req->sbal_last = req_q->first;
733 req->sbale_curr = 1;
734
735 sbale = zfcp_qdio_sbale_req(req);
736 sbale[0].addr = (void *) req->req_id;
737 sbale[0].flags |= SBAL_FLAGS0_COMMAND;
738
739 if (likely(req->qtcb)) {
740 req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no;
741 req->qtcb->prefix.req_id = req->req_id;
742 req->qtcb->prefix.ulp_info = 26;
743 req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command];
744 req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
745 req->qtcb->header.req_handle = req->req_id;
746 req->qtcb->header.fsf_command = req->fsf_command;
747 req->seq_no = adapter->fsf_req_seq_no;
748 req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
749 sbale[1].addr = (void *) req->qtcb;
750 sbale[1].length = sizeof(struct fsf_qtcb);
751 }
752
753 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
754 zfcp_fsf_req_free(req);
755 return ERR_PTR(-EIO);
756 }
757
758 if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP))
759 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
760
761 return req;
762}
763
764static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
765{
766 struct zfcp_adapter *adapter = req->adapter;
Heiko Carstens45316a82008-11-04 16:35:06 +0100767 unsigned long flags;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200768 int idx;
769
770 /* put allocated FSF request into hash table */
Heiko Carstens45316a82008-11-04 16:35:06 +0100771 spin_lock_irqsave(&adapter->req_list_lock, flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200772 idx = zfcp_reqlist_hash(req->req_id);
773 list_add_tail(&req->list, &adapter->req_list[idx]);
Heiko Carstens45316a82008-11-04 16:35:06 +0100774 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200775
Christof Schmitt37651382008-11-04 16:35:08 +0100776 req->qdio_outb_usage = atomic_read(&adapter->req_q.count);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200777 req->issued = get_clock();
778 if (zfcp_qdio_send(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200779 del_timer(&req->timer);
Christof Schmitt37651382008-11-04 16:35:08 +0100780 spin_lock_irqsave(&adapter->req_list_lock, flags);
781 /* lookup request again, list might have changed */
782 if (zfcp_reqlist_find_safe(adapter, req))
783 zfcp_reqlist_remove(adapter, req);
784 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100785 zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200786 return -EIO;
787 }
788
789 /* Don't increase for unsolicited status */
790 if (req->qtcb)
791 adapter->fsf_req_seq_no++;
Christof Schmitt52bfb552009-03-02 13:08:58 +0100792 adapter->req_no++;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200793
794 return 0;
795}
796
797/**
798 * zfcp_fsf_status_read - send status read request
799 * @adapter: pointer to struct zfcp_adapter
800 * @req_flags: request flags
801 * Returns: 0 on success, ERROR otherwise
802 */
803int zfcp_fsf_status_read(struct zfcp_adapter *adapter)
804{
805 struct zfcp_fsf_req *req;
806 struct fsf_status_read_buffer *sr_buf;
Swen Schillig44cc76f2008-10-01 12:42:16 +0200807 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200808 int retval = -EIO;
809
Christof Schmitt04062892008-10-01 12:42:20 +0200810 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200811 if (zfcp_fsf_req_sbal_get(adapter))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200814 req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
815 ZFCP_REQ_NO_QTCB,
816 adapter->pool.fsf_req_status_read);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +0200817 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200818 retval = PTR_ERR(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 goto out;
820 }
821
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200822 sbale = zfcp_qdio_sbale_req(req);
823 sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
824 sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
825 req->sbale_curr = 2;
826
827 sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
828 if (!sr_buf) {
829 retval = -ENOMEM;
830 goto failed_buf;
831 }
832 memset(sr_buf, 0, sizeof(*sr_buf));
833 req->data = sr_buf;
834 sbale = zfcp_qdio_sbale_curr(req);
835 sbale->addr = (void *) sr_buf;
836 sbale->length = sizeof(*sr_buf);
837
838 retval = zfcp_fsf_req_send(req);
839 if (retval)
840 goto failed_req_send;
841
842 goto out;
843
844failed_req_send:
845 mempool_free(sr_buf, adapter->pool.data_status_read);
846failed_buf:
847 zfcp_fsf_req_free(req);
848 zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
849out:
Christof Schmitt04062892008-10-01 12:42:20 +0200850 spin_unlock_bh(&adapter->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return retval;
852}
853
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200854static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200856 struct zfcp_unit *unit = req->data;
857 union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200859 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
860 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200862 switch (req->qtcb->header.fsf_status) {
863 case FSF_PORT_HANDLE_NOT_VALID:
864 if (fsq->word[0] == fsq->word[1]) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100865 zfcp_erp_adapter_reopen(unit->port->adapter, 0,
866 "fsafch1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200867 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200870 case FSF_LUN_HANDLE_NOT_VALID:
871 if (fsq->word[0] == fsq->word[1]) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100872 zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200873 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200876 case FSF_FCP_COMMAND_DOES_NOT_EXIST:
877 req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 break;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200879 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100880 zfcp_erp_port_boxed(unit->port, "fsafch3", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200881 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
882 ZFCP_STATUS_FSFREQ_RETRY;
883 break;
884 case FSF_LUN_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100885 zfcp_erp_unit_boxed(unit, "fsafch4", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200886 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
887 ZFCP_STATUS_FSFREQ_RETRY;
888 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 case FSF_ADAPTER_STATUS_AVAILABLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200890 switch (fsq->word[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200892 zfcp_test_link(unit->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200894 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 break;
896 }
897 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 case FSF_GOOD:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200899 req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
900 break;
901 }
902}
903
904/**
905 * zfcp_fsf_abort_fcp_command - abort running SCSI command
906 * @old_req_id: unsigned long
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200907 * @unit: pointer to struct zfcp_unit
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200908 * Returns: pointer to struct zfcp_fsf_req
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200909 */
910
911struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
Christof Schmitt63caf362009-03-02 13:09:00 +0100912 struct zfcp_unit *unit)
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200913{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200914 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200915 struct zfcp_fsf_req *req = NULL;
Christof Schmitt63caf362009-03-02 13:09:00 +0100916 struct zfcp_adapter *adapter = unit->port->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200917
Christof Schmitt92cab0d2009-03-02 13:08:59 +0100918 spin_lock_bh(&adapter->req_q_lock);
919 if (zfcp_fsf_req_sbal_get(adapter))
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200920 goto out;
921 req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
Christof Schmitt63caf362009-03-02 13:09:00 +0100922 0, adapter->pool.fsf_req_abort);
Swen Schillig633528c2008-11-26 18:07:37 +0100923 if (IS_ERR(req)) {
924 req = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200925 goto out;
Swen Schillig633528c2008-11-26 18:07:37 +0100926 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200927
928 if (unlikely(!(atomic_read(&unit->status) &
929 ZFCP_STATUS_COMMON_UNBLOCKED)))
930 goto out_error_free;
931
932 sbale = zfcp_qdio_sbale_req(req);
933 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
934 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
935
936 req->data = unit;
937 req->handler = zfcp_fsf_abort_fcp_command_handler;
938 req->qtcb->header.lun_handle = unit->handle;
939 req->qtcb->header.port_handle = unit->port->handle;
940 req->qtcb->bottom.support.req_handle = (u64) old_req_id;
941
942 zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
943 if (!zfcp_fsf_req_send(req))
944 goto out;
945
946out_error_free:
947 zfcp_fsf_req_free(req);
948 req = NULL;
949out:
Christof Schmitt92cab0d2009-03-02 13:08:59 +0100950 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200951 return req;
952}
953
954static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
955{
956 struct zfcp_adapter *adapter = req->adapter;
957 struct zfcp_send_ct *send_ct = req->data;
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200958 struct fsf_qtcb_header *header = &req->qtcb->header;
959
960 send_ct->status = -EINVAL;
961
962 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
963 goto skip_fsfstatus;
964
965 switch (header->fsf_status) {
966 case FSF_GOOD:
967 zfcp_san_dbf_event_ct_response(req);
968 send_ct->status = 0;
969 break;
970 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
971 zfcp_fsf_class_not_supp(req);
972 break;
973 case FSF_ADAPTER_STATUS_AVAILABLE:
974 switch (header->fsf_status_qual.word[0]){
975 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200976 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
977 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
978 break;
979 }
980 break;
981 case FSF_ACCESS_DENIED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200982 break;
983 case FSF_PORT_BOXED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200984 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
985 ZFCP_STATUS_FSFREQ_RETRY;
986 break;
987 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100988 zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +0200989 case FSF_GENERIC_COMMAND_REJECTED:
990 case FSF_PAYLOAD_SIZE_MISMATCH:
991 case FSF_REQUEST_SIZE_TOO_LARGE:
992 case FSF_RESPONSE_SIZE_TOO_LARGE:
993 case FSF_SBAL_MISMATCH:
994 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
995 break;
996 }
997
998skip_fsfstatus:
999 if (send_ct->handler)
1000 send_ct->handler(send_ct->handler_data);
1001}
1002
Christof Schmitt39eb7e92008-12-19 16:57:01 +01001003static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
1004 struct scatterlist *sg_req,
1005 struct scatterlist *sg_resp,
1006 int max_sbals)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001007{
Christof Schmitt39eb7e92008-12-19 16:57:01 +01001008 struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req);
1009 u32 feat = req->adapter->adapter_features;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001010 int bytes;
1011
Christof Schmitt39eb7e92008-12-19 16:57:01 +01001012 if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
1013 if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
1014 !sg_is_last(sg_req) || !sg_is_last(sg_resp))
1015 return -EOPNOTSUPP;
1016
1017 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
1018 sbale[2].addr = sg_virt(sg_req);
1019 sbale[2].length = sg_req->length;
1020 sbale[3].addr = sg_virt(sg_resp);
1021 sbale[3].length = sg_resp->length;
1022 sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
1023 return 0;
1024 }
1025
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001026 bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1027 sg_req, max_sbals);
1028 if (bytes <= 0)
1029 return -ENOMEM;
1030 req->qtcb->bottom.support.req_buf_length = bytes;
1031 req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
1032
1033 bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
1034 sg_resp, max_sbals);
1035 if (bytes <= 0)
1036 return -ENOMEM;
1037 req->qtcb->bottom.support.resp_buf_length = bytes;
1038
1039 return 0;
1040}
1041
1042/**
1043 * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1044 * @ct: pointer to struct zfcp_send_ct with data for request
1045 * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req
1046 * @erp_action: if non-null the Generic Service request sent within ERP
1047 */
1048int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
1049 struct zfcp_erp_action *erp_action)
1050{
Swen Schillig5ab944f2008-10-01 12:42:17 +02001051 struct zfcp_wka_port *wka_port = ct->wka_port;
1052 struct zfcp_adapter *adapter = wka_port->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001053 struct zfcp_fsf_req *req;
1054 int ret = -EIO;
1055
Christof Schmitt04062892008-10-01 12:42:20 +02001056 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001057 if (zfcp_fsf_req_sbal_get(adapter))
1058 goto out;
1059
1060 req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
1061 ZFCP_REQ_AUTO_CLEANUP, pool);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001062 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001063 ret = PTR_ERR(req);
1064 goto out;
1065 }
1066
Christof Schmitt39eb7e92008-12-19 16:57:01 +01001067 ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp,
1068 FSF_MAX_SBALS_PER_REQ);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001069 if (ret)
1070 goto failed_send;
1071
1072 req->handler = zfcp_fsf_send_ct_handler;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001073 req->qtcb->header.port_handle = wka_port->handle;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001074 req->qtcb->bottom.support.service_class = FSF_CLASS_3;
1075 req->qtcb->bottom.support.timeout = ct->timeout;
1076 req->data = ct;
1077
1078 zfcp_san_dbf_event_ct_request(req);
1079
1080 if (erp_action) {
1081 erp_action->fsf_req = req;
1082 req->erp_action = erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +02001083 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001084 } else
1085 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1086
1087 ret = zfcp_fsf_req_send(req);
1088 if (ret)
1089 goto failed_send;
1090
1091 goto out;
1092
1093failed_send:
1094 zfcp_fsf_req_free(req);
1095 if (erp_action)
1096 erp_action->fsf_req = NULL;
1097out:
Christof Schmitt04062892008-10-01 12:42:20 +02001098 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001099 return ret;
1100}
1101
1102static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
1103{
1104 struct zfcp_send_els *send_els = req->data;
1105 struct zfcp_port *port = send_els->port;
1106 struct fsf_qtcb_header *header = &req->qtcb->header;
1107
1108 send_els->status = -EINVAL;
1109
1110 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
1111 goto skip_fsfstatus;
1112
1113 switch (header->fsf_status) {
1114 case FSF_GOOD:
1115 zfcp_san_dbf_event_els_response(req);
1116 send_els->status = 0;
1117 break;
1118 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
1119 zfcp_fsf_class_not_supp(req);
1120 break;
1121 case FSF_ADAPTER_STATUS_AVAILABLE:
1122 switch (header->fsf_status_qual.word[0]){
1123 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1124 if (port && (send_els->ls_code != ZFCP_LS_ADISC))
1125 zfcp_test_link(port);
1126 /*fall through */
1127 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1128 case FSF_SQ_RETRY_IF_POSSIBLE:
1129 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1130 break;
1131 }
1132 break;
1133 case FSF_ELS_COMMAND_REJECTED:
1134 case FSF_PAYLOAD_SIZE_MISMATCH:
1135 case FSF_REQUEST_SIZE_TOO_LARGE:
1136 case FSF_RESPONSE_SIZE_TOO_LARGE:
1137 break;
1138 case FSF_ACCESS_DENIED:
1139 zfcp_fsf_access_denied_port(req, port);
1140 break;
1141 case FSF_SBAL_MISMATCH:
1142 /* should never occure, avoided in zfcp_fsf_send_els */
1143 /* fall through */
1144 default:
1145 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1146 break;
1147 }
1148skip_fsfstatus:
1149 if (send_els->handler)
1150 send_els->handler(send_els->handler_data);
1151}
1152
1153/**
1154 * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1155 * @els: pointer to struct zfcp_send_els with data for the command
1156 */
1157int zfcp_fsf_send_els(struct zfcp_send_els *els)
1158{
1159 struct zfcp_fsf_req *req;
1160 struct zfcp_adapter *adapter = els->adapter;
1161 struct fsf_qtcb_bottom_support *bottom;
1162 int ret = -EIO;
1163
1164 if (unlikely(!(atomic_read(&els->port->status) &
1165 ZFCP_STATUS_COMMON_UNBLOCKED)))
1166 return -EBUSY;
1167
Christof Schmitt8fdf30d2009-03-02 13:09:01 +01001168 spin_lock_bh(&adapter->req_q_lock);
1169 if (zfcp_fsf_req_sbal_get(adapter))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001170 goto out;
1171 req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
1172 ZFCP_REQ_AUTO_CLEANUP, NULL);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001173 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001174 ret = PTR_ERR(req);
1175 goto out;
1176 }
1177
Christof Schmitt39eb7e92008-12-19 16:57:01 +01001178 ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2);
Swen Schillig44cc76f2008-10-01 12:42:16 +02001179
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001180 if (ret)
1181 goto failed_send;
1182
1183 bottom = &req->qtcb->bottom.support;
1184 req->handler = zfcp_fsf_send_els_handler;
1185 bottom->d_id = els->d_id;
1186 bottom->service_class = FSF_CLASS_3;
1187 bottom->timeout = 2 * R_A_TOV;
1188 req->data = els;
1189
1190 zfcp_san_dbf_event_els_request(req);
1191
1192 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1193 ret = zfcp_fsf_req_send(req);
1194 if (ret)
1195 goto failed_send;
1196
1197 goto out;
1198
1199failed_send:
1200 zfcp_fsf_req_free(req);
1201out:
Christof Schmitt8fdf30d2009-03-02 13:09:01 +01001202 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001203 return ret;
1204}
1205
1206int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
1207{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001208 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001209 struct zfcp_fsf_req *req;
1210 struct zfcp_adapter *adapter = erp_action->adapter;
1211 int retval = -EIO;
1212
Christof Schmitt04062892008-10-01 12:42:20 +02001213 spin_lock_bh(&adapter->req_q_lock);
Christof Schmitt92cab0d2009-03-02 13:08:59 +01001214 if (zfcp_fsf_req_sbal_get(adapter))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001215 goto out;
1216 req = zfcp_fsf_req_create(adapter,
1217 FSF_QTCB_EXCHANGE_CONFIG_DATA,
1218 ZFCP_REQ_AUTO_CLEANUP,
1219 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001220 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001221 retval = PTR_ERR(req);
1222 goto out;
1223 }
1224
1225 sbale = zfcp_qdio_sbale_req(req);
1226 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1227 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1228
1229 req->qtcb->bottom.config.feature_selection =
1230 FSF_FEATURE_CFDC |
1231 FSF_FEATURE_LUN_SHARING |
1232 FSF_FEATURE_NOTIFICATION_LOST |
1233 FSF_FEATURE_UPDATE_ALERT;
1234 req->erp_action = erp_action;
1235 req->handler = zfcp_fsf_exchange_config_data_handler;
1236 erp_action->fsf_req = req;
1237
Christof Schmitt287ac012008-07-02 10:56:40 +02001238 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001239 retval = zfcp_fsf_req_send(req);
1240 if (retval) {
1241 zfcp_fsf_req_free(req);
1242 erp_action->fsf_req = NULL;
1243 }
1244out:
Christof Schmitt04062892008-10-01 12:42:20 +02001245 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001246 return retval;
1247}
1248
1249int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
1250 struct fsf_qtcb_bottom_config *data)
1251{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001252 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001253 struct zfcp_fsf_req *req = NULL;
1254 int retval = -EIO;
1255
Christof Schmitt04062892008-10-01 12:42:20 +02001256 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001257 if (zfcp_fsf_req_sbal_get(adapter))
1258 goto out;
1259
1260 req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
1261 0, NULL);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001262 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001263 retval = PTR_ERR(req);
1264 goto out;
1265 }
1266
1267 sbale = zfcp_qdio_sbale_req(req);
1268 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1269 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1270 req->handler = zfcp_fsf_exchange_config_data_handler;
1271
1272 req->qtcb->bottom.config.feature_selection =
1273 FSF_FEATURE_CFDC |
1274 FSF_FEATURE_LUN_SHARING |
1275 FSF_FEATURE_NOTIFICATION_LOST |
1276 FSF_FEATURE_UPDATE_ALERT;
1277
1278 if (data)
1279 req->data = data;
1280
1281 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1282 retval = zfcp_fsf_req_send(req);
1283out:
Christof Schmitt04062892008-10-01 12:42:20 +02001284 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001285 if (!retval)
1286 wait_event(req->completion_wq,
1287 req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
1288
1289 zfcp_fsf_req_free(req);
1290
1291 return retval;
1292}
1293
1294/**
1295 * zfcp_fsf_exchange_port_data - request information about local port
1296 * @erp_action: ERP action for the adapter for which port data is requested
1297 * Returns: 0 on success, error otherwise
1298 */
1299int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
1300{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001301 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001302 struct zfcp_fsf_req *req;
1303 struct zfcp_adapter *adapter = erp_action->adapter;
1304 int retval = -EIO;
1305
1306 if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
1307 return -EOPNOTSUPP;
1308
Christof Schmitt04062892008-10-01 12:42:20 +02001309 spin_lock_bh(&adapter->req_q_lock);
Christof Schmitt92cab0d2009-03-02 13:08:59 +01001310 if (zfcp_fsf_req_sbal_get(adapter))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001311 goto out;
1312 req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
1313 ZFCP_REQ_AUTO_CLEANUP,
1314 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001315 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001316 retval = PTR_ERR(req);
1317 goto out;
1318 }
1319
1320 sbale = zfcp_qdio_sbale_req(req);
1321 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1322 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1323
1324 req->handler = zfcp_fsf_exchange_port_data_handler;
1325 req->erp_action = erp_action;
1326 erp_action->fsf_req = req;
1327
Christof Schmitt287ac012008-07-02 10:56:40 +02001328 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001329 retval = zfcp_fsf_req_send(req);
1330 if (retval) {
1331 zfcp_fsf_req_free(req);
1332 erp_action->fsf_req = NULL;
1333 }
1334out:
Christof Schmitt04062892008-10-01 12:42:20 +02001335 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001336 return retval;
1337}
1338
1339/**
1340 * zfcp_fsf_exchange_port_data_sync - request information about local port
1341 * @adapter: pointer to struct zfcp_adapter
1342 * @data: pointer to struct fsf_qtcb_bottom_port
1343 * Returns: 0 on success, error otherwise
1344 */
1345int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
1346 struct fsf_qtcb_bottom_port *data)
1347{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001348 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001349 struct zfcp_fsf_req *req = NULL;
1350 int retval = -EIO;
1351
1352 if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
1353 return -EOPNOTSUPP;
1354
Christof Schmitt04062892008-10-01 12:42:20 +02001355 spin_lock_bh(&adapter->req_q_lock);
Christof Schmitt92cab0d2009-03-02 13:08:59 +01001356 if (zfcp_fsf_req_sbal_get(adapter))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001357 goto out;
1358
1359 req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
1360 NULL);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001361 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001362 retval = PTR_ERR(req);
1363 goto out;
1364 }
1365
1366 if (data)
1367 req->data = data;
1368
1369 sbale = zfcp_qdio_sbale_req(req);
1370 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1371 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1372
1373 req->handler = zfcp_fsf_exchange_port_data_handler;
1374 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1375 retval = zfcp_fsf_req_send(req);
1376out:
Christof Schmitt04062892008-10-01 12:42:20 +02001377 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001378 if (!retval)
1379 wait_event(req->completion_wq,
1380 req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
1381 zfcp_fsf_req_free(req);
1382
1383 return retval;
1384}
1385
1386static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
1387{
1388 struct zfcp_port *port = req->data;
1389 struct fsf_qtcb_header *header = &req->qtcb->header;
1390 struct fsf_plogi *plogi;
1391
1392 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001393 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001394
1395 switch (header->fsf_status) {
1396 case FSF_PORT_ALREADY_OPEN:
1397 break;
1398 case FSF_ACCESS_DENIED:
1399 zfcp_fsf_access_denied_port(req, port);
1400 break;
1401 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1402 dev_warn(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001403 "Not enough FCP adapter resources to open "
Swen Schillig7ba58c92008-10-01 12:42:18 +02001404 "remote port 0x%016Lx\n",
1405 (unsigned long long)port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001406 zfcp_erp_port_failed(port, "fsoph_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001407 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1408 break;
1409 case FSF_ADAPTER_STATUS_AVAILABLE:
1410 switch (header->fsf_status_qual.word[0]) {
1411 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1412 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001413 case FSF_SQ_NO_RETRY_POSSIBLE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001414 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1415 break;
1416 }
1417 break;
1418 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 port->handle = header->port_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
1421 ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Andreas Herrmannd736a272005-06-13 13:23:57 +02001422 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
1423 ZFCP_STATUS_COMMON_ACCESS_BOXED,
1424 &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 /* check whether D_ID has changed during open */
1426 /*
1427 * FIXME: This check is not airtight, as the FCP channel does
1428 * not monitor closures of target port connections caused on
1429 * the remote side. Thus, they might miss out on invalidating
1430 * locally cached WWPNs (and other N_Port parameters) of gone
1431 * target ports. So, our heroic attempt to make things safe
1432 * could be undermined by 'open port' response data tagged with
1433 * obsolete WWPNs. Another reason to monitor potential
1434 * connection closures ourself at least (by interpreting
1435 * incoming ELS' and unsolicited status). It just crosses my
1436 * mind that one should be able to cross-check by means of
1437 * another GID_PN straight after a port has been opened.
1438 * Alternately, an ADISC/PDISC ELS should suffice, as well.
1439 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001440 plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
Christof Schmitt39eb7e92008-12-19 16:57:01 +01001441 if (req->qtcb->bottom.support.els1_length >=
1442 FSF_PLOGI_MIN_LEN) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001443 if (plogi->serv_param.wwpn != port->wwpn)
Christof Schmittb98478d2008-12-19 16:56:59 +01001444 port->d_id = 0;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001445 else {
1446 port->wwnn = plogi->serv_param.wwnn;
1447 zfcp_fc_plogi_evaluate(port, plogi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 }
1449 }
1450 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 case FSF_UNKNOWN_OP_SUBTYPE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001452 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 break;
1454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455}
1456
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001457/**
1458 * zfcp_fsf_open_port - create and send open port request
1459 * @erp_action: pointer to struct zfcp_erp_action
1460 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001462int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001464 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001465 struct zfcp_adapter *adapter = erp_action->adapter;
1466 struct zfcp_fsf_req *req;
1467 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Christof Schmitt04062892008-10-01 12:42:20 +02001469 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001470 if (zfcp_fsf_req_sbal_get(adapter))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001473 req = zfcp_fsf_req_create(adapter,
1474 FSF_QTCB_OPEN_PORT_WITH_DID,
1475 ZFCP_REQ_AUTO_CLEANUP,
1476 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001477 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001478 retval = PTR_ERR(req);
1479 goto out;
1480 }
1481
1482 sbale = zfcp_qdio_sbale_req(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1484 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1485
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001486 req->handler = zfcp_fsf_open_port_handler;
1487 req->qtcb->bottom.support.d_id = erp_action->port->d_id;
1488 req->data = erp_action->port;
1489 req->erp_action = erp_action;
1490 erp_action->fsf_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Christof Schmitt287ac012008-07-02 10:56:40 +02001492 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001493 retval = zfcp_fsf_req_send(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (retval) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001495 zfcp_fsf_req_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 erp_action->fsf_req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001498out:
Christof Schmitt04062892008-10-01 12:42:20 +02001499 spin_unlock_bh(&adapter->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 return retval;
1501}
1502
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001503static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001505 struct zfcp_port *port = req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001507 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001508 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001510 switch (req->qtcb->header.fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001512 zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001513 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 case FSF_GOOD:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001518 zfcp_erp_modify_port_status(port, "fscph_2", req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 ZFCP_STATUS_COMMON_OPEN,
1520 ZFCP_CLEAR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523}
1524
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001525/**
1526 * zfcp_fsf_close_port - create and send close port request
1527 * @erp_action: pointer to struct zfcp_erp_action
1528 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001530int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001532 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001533 struct zfcp_adapter *adapter = erp_action->adapter;
1534 struct zfcp_fsf_req *req;
1535 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
Christof Schmitt04062892008-10-01 12:42:20 +02001537 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001538 if (zfcp_fsf_req_sbal_get(adapter))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001541 req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
1542 ZFCP_REQ_AUTO_CLEANUP,
1543 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001544 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001545 retval = PTR_ERR(req);
1546 goto out;
1547 }
1548
1549 sbale = zfcp_qdio_sbale_req(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1551 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1552
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001553 req->handler = zfcp_fsf_close_port_handler;
1554 req->data = erp_action->port;
1555 req->erp_action = erp_action;
1556 req->qtcb->header.port_handle = erp_action->port->handle;
1557 erp_action->fsf_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Christof Schmitt287ac012008-07-02 10:56:40 +02001559 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001560 retval = zfcp_fsf_req_send(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 if (retval) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001562 zfcp_fsf_req_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 erp_action->fsf_req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001565out:
Christof Schmitt04062892008-10-01 12:42:20 +02001566 spin_unlock_bh(&adapter->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return retval;
1568}
1569
Swen Schillig5ab944f2008-10-01 12:42:17 +02001570static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
1571{
1572 struct zfcp_wka_port *wka_port = req->data;
1573 struct fsf_qtcb_header *header = &req->qtcb->header;
1574
1575 if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
1576 wka_port->status = ZFCP_WKA_PORT_OFFLINE;
1577 goto out;
1578 }
1579
1580 switch (header->fsf_status) {
1581 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
1582 dev_warn(&req->adapter->ccw_device->dev,
1583 "Opening WKA port 0x%x failed\n", wka_port->d_id);
1584 case FSF_ADAPTER_STATUS_AVAILABLE:
1585 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1586 case FSF_ACCESS_DENIED:
1587 wka_port->status = ZFCP_WKA_PORT_OFFLINE;
1588 break;
1589 case FSF_PORT_ALREADY_OPEN:
Christof Schmitt1c1cba12008-11-26 18:07:36 +01001590 break;
Swen Schillig5ab944f2008-10-01 12:42:17 +02001591 case FSF_GOOD:
1592 wka_port->handle = header->port_handle;
1593 wka_port->status = ZFCP_WKA_PORT_ONLINE;
1594 }
1595out:
1596 wake_up(&wka_port->completion_wq);
1597}
1598
1599/**
1600 * zfcp_fsf_open_wka_port - create and send open wka-port request
1601 * @wka_port: pointer to struct zfcp_wka_port
1602 * Returns: 0 on success, error otherwise
1603 */
1604int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
1605{
1606 struct qdio_buffer_element *sbale;
1607 struct zfcp_adapter *adapter = wka_port->adapter;
1608 struct zfcp_fsf_req *req;
1609 int retval = -EIO;
1610
Christof Schmitt04062892008-10-01 12:42:20 +02001611 spin_lock_bh(&adapter->req_q_lock);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001612 if (zfcp_fsf_req_sbal_get(adapter))
1613 goto out;
1614
1615 req = zfcp_fsf_req_create(adapter,
1616 FSF_QTCB_OPEN_PORT_WITH_DID,
1617 ZFCP_REQ_AUTO_CLEANUP,
1618 adapter->pool.fsf_req_erp);
1619 if (unlikely(IS_ERR(req))) {
1620 retval = PTR_ERR(req);
1621 goto out;
1622 }
1623
1624 sbale = zfcp_qdio_sbale_req(req);
1625 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1626 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1627
1628 req->handler = zfcp_fsf_open_wka_port_handler;
1629 req->qtcb->bottom.support.d_id = wka_port->d_id;
1630 req->data = wka_port;
1631
1632 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1633 retval = zfcp_fsf_req_send(req);
1634 if (retval)
1635 zfcp_fsf_req_free(req);
1636out:
Christof Schmitt04062892008-10-01 12:42:20 +02001637 spin_unlock_bh(&adapter->req_q_lock);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001638 return retval;
1639}
1640
1641static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
1642{
1643 struct zfcp_wka_port *wka_port = req->data;
1644
1645 if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
1646 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001647 zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001648 }
1649
1650 wka_port->status = ZFCP_WKA_PORT_OFFLINE;
1651 wake_up(&wka_port->completion_wq);
1652}
1653
1654/**
1655 * zfcp_fsf_close_wka_port - create and send close wka port request
1656 * @erp_action: pointer to struct zfcp_erp_action
1657 * Returns: 0 on success, error otherwise
1658 */
1659int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
1660{
1661 struct qdio_buffer_element *sbale;
1662 struct zfcp_adapter *adapter = wka_port->adapter;
1663 struct zfcp_fsf_req *req;
1664 int retval = -EIO;
1665
Christof Schmitt04062892008-10-01 12:42:20 +02001666 spin_lock_bh(&adapter->req_q_lock);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001667 if (zfcp_fsf_req_sbal_get(adapter))
1668 goto out;
1669
1670 req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
1671 ZFCP_REQ_AUTO_CLEANUP,
1672 adapter->pool.fsf_req_erp);
1673 if (unlikely(IS_ERR(req))) {
1674 retval = PTR_ERR(req);
1675 goto out;
1676 }
1677
1678 sbale = zfcp_qdio_sbale_req(req);
1679 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1680 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1681
1682 req->handler = zfcp_fsf_close_wka_port_handler;
1683 req->data = wka_port;
1684 req->qtcb->header.port_handle = wka_port->handle;
1685
1686 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
1687 retval = zfcp_fsf_req_send(req);
1688 if (retval)
1689 zfcp_fsf_req_free(req);
1690out:
Christof Schmitt04062892008-10-01 12:42:20 +02001691 spin_unlock_bh(&adapter->req_q_lock);
Swen Schillig5ab944f2008-10-01 12:42:17 +02001692 return retval;
1693}
1694
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001695static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001697 struct zfcp_port *port = req->data;
1698 struct fsf_qtcb_header *header = &req->qtcb->header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 struct zfcp_unit *unit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001701 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Christof Schmitta5b11dd2009-03-02 13:08:54 +01001702 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 switch (header->fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001706 zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001707 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 case FSF_ACCESS_DENIED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001710 zfcp_fsf_access_denied_port(req, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001713 zfcp_erp_port_boxed(port, "fscpph2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001714 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1715 ZFCP_STATUS_FSFREQ_RETRY;
Christof Schmitt5c815d12008-03-10 16:18:54 +01001716 /* can't use generic zfcp_erp_modify_port_status because
1717 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
1718 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
1719 list_for_each_entry(unit, &port->unit_list_head, list)
1720 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1721 &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 switch (header->fsf_status_qual.word[0]) {
1725 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001726 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001728 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
1731 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* can't use generic zfcp_erp_modify_port_status because
1734 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
1735 */
1736 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
1737 list_for_each_entry(unit, &port->unit_list_head, list)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001738 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
1739 &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742}
1743
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001744/**
1745 * zfcp_fsf_close_physical_port - close physical port
1746 * @erp_action: pointer to struct zfcp_erp_action
1747 * Returns: 0 on success
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001749int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001751 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001752 struct zfcp_adapter *adapter = erp_action->adapter;
1753 struct zfcp_fsf_req *req;
1754 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
Christof Schmitt04062892008-10-01 12:42:20 +02001756 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001757 if (zfcp_fsf_req_sbal_get(adapter))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001760 req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT,
1761 ZFCP_REQ_AUTO_CLEANUP,
1762 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001763 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001764 retval = PTR_ERR(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 goto out;
1766 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001767
1768 sbale = zfcp_qdio_sbale_req(req);
1769 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1770 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1771
1772 req->data = erp_action->port;
1773 req->qtcb->header.port_handle = erp_action->port->handle;
1774 req->erp_action = erp_action;
1775 req->handler = zfcp_fsf_close_physical_port_handler;
1776 erp_action->fsf_req = req;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001777
Christof Schmitt287ac012008-07-02 10:56:40 +02001778 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001779 retval = zfcp_fsf_req_send(req);
1780 if (retval) {
1781 zfcp_fsf_req_free(req);
1782 erp_action->fsf_req = NULL;
1783 }
1784out:
Christof Schmitt04062892008-10-01 12:42:20 +02001785 spin_unlock_bh(&adapter->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 return retval;
1787}
1788
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001789static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001791 struct zfcp_adapter *adapter = req->adapter;
1792 struct zfcp_unit *unit = req->data;
1793 struct fsf_qtcb_header *header = &req->qtcb->header;
1794 struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support;
1795 struct fsf_queue_designator *queue_designator =
1796 &header->fsf_status_qual.fsf_queue_designator;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001797 int exclusive, readwrite;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001799 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001800 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Heiko Carstensb64ddf92007-05-08 11:19:57 +02001803 ZFCP_STATUS_COMMON_ACCESS_BOXED |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 ZFCP_STATUS_UNIT_SHARED |
1805 ZFCP_STATUS_UNIT_READONLY,
1806 &unit->status);
1807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 switch (header->fsf_status) {
1809
1810 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001811 zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001812 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 case FSF_LUN_ALREADY_OPEN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 case FSF_ACCESS_DENIED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001816 zfcp_fsf_access_denied_unit(req, unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
Christof Schmitt553448f2008-06-10 18:20:58 +02001818 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001821 zfcp_erp_port_boxed(unit->port, "fsouh_2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001822 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1823 ZFCP_STATUS_FSFREQ_RETRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 case FSF_LUN_SHARING_VIOLATION:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001826 if (header->fsf_status_qual.word[0])
Christof Schmitt553448f2008-06-10 18:20:58 +02001827 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001828 "LUN 0x%Lx on port 0x%Lx is already in "
1829 "use by CSS%d, MIF Image ID %x\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001830 (unsigned long long)unit->fcp_lun,
1831 (unsigned long long)unit->port->wwpn,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001832 queue_designator->cssid,
1833 queue_designator->hla);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001834 else
Christof Schmitt553448f2008-06-10 18:20:58 +02001835 zfcp_act_eval_err(adapter,
1836 header->fsf_status_qual.word[2]);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001837 zfcp_erp_unit_access_denied(unit, "fsouh_3", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
1839 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001840 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001843 dev_warn(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001844 "No handle is available for LUN "
1845 "0x%016Lx on port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001846 (unsigned long long)unit->fcp_lun,
1847 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001848 zfcp_erp_unit_failed(unit, "fsouh_4", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001849 /* fall through */
1850 case FSF_INVALID_COMMAND_OPTION:
1851 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 switch (header->fsf_status_qual.word[0]) {
1855 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Andreas Herrmann65a8d4e2005-06-13 13:16:27 +02001856 zfcp_test_link(unit->port);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001857 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001859 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 }
1862 break;
1863
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 unit->handle = header->lun_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001867
1868 if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
1869 (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
1870 (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
1871 exclusive = (bottom->lun_access_info &
1872 FSF_UNIT_ACCESS_EXCLUSIVE);
1873 readwrite = (bottom->lun_access_info &
1874 FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (!exclusive)
1877 atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
1878 &unit->status);
1879
1880 if (!readwrite) {
1881 atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
1882 &unit->status);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001883 dev_info(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001884 "SCSI device at LUN 0x%016Lx on port "
1885 "0x%016Lx opened read-only\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001886 (unsigned long long)unit->fcp_lun,
1887 (unsigned long long)unit->port->wwpn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 }
1889
1890 if (exclusive && !readwrite) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001891 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001892 "Exclusive read-only access not "
1893 "supported (unit 0x%016Lx, "
1894 "port 0x%016Lx)\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001895 (unsigned long long)unit->fcp_lun,
1896 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001897 zfcp_erp_unit_failed(unit, "fsouh_5", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001898 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001899 zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 } else if (!exclusive && readwrite) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001901 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001902 "Shared read-write access not "
1903 "supported (unit 0x%016Lx, port "
Christof Schmitt27c3f0a2008-12-19 16:56:52 +01001904 "0x%016Lx)\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001905 (unsigned long long)unit->fcp_lun,
1906 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001907 zfcp_erp_unit_failed(unit, "fsouh_7", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001908 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001909 zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 }
1911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914}
1915
1916/**
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001917 * zfcp_fsf_open_unit - open unit
1918 * @erp_action: pointer to struct zfcp_erp_action
1919 * Returns: 0 on success, error otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001921int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
Swen Schillig44cc76f2008-10-01 12:42:16 +02001923 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001924 struct zfcp_adapter *adapter = erp_action->adapter;
1925 struct zfcp_fsf_req *req;
1926 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
Christof Schmitt04062892008-10-01 12:42:20 +02001928 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001929 if (zfcp_fsf_req_sbal_get(adapter))
1930 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001932 req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN,
1933 ZFCP_REQ_AUTO_CLEANUP,
1934 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02001935 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001936 retval = PTR_ERR(req);
1937 goto out;
Christof Schmittba172422007-12-20 12:30:26 +01001938 }
1939
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001940 sbale = zfcp_qdio_sbale_req(req);
1941 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1942 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001944 req->qtcb->header.port_handle = erp_action->port->handle;
1945 req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
1946 req->handler = zfcp_fsf_open_unit_handler;
1947 req->data = erp_action->unit;
1948 req->erp_action = erp_action;
1949 erp_action->fsf_req = req;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001950
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001951 if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
1952 req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
Christof Schmitt287ac012008-07-02 10:56:40 +02001954 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001955 retval = zfcp_fsf_req_send(req);
1956 if (retval) {
1957 zfcp_fsf_req_free(req);
1958 erp_action->fsf_req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001960out:
Christof Schmitt04062892008-10-01 12:42:20 +02001961 spin_unlock_bh(&adapter->req_q_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 return retval;
1963}
1964
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001965static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001967 struct zfcp_unit *unit = req->data;
1968
1969 if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
Swen Schillig44cc76f2008-10-01 12:42:16 +02001970 return;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001971
1972 switch (req->qtcb->header.fsf_status) {
1973 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001974 zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001975 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1976 break;
1977 case FSF_LUN_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001978 zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001979 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1980 break;
1981 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001982 zfcp_erp_port_boxed(unit->port, "fscuh_3", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02001983 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
1984 ZFCP_STATUS_FSFREQ_RETRY;
1985 break;
1986 case FSF_ADAPTER_STATUS_AVAILABLE:
1987 switch (req->qtcb->header.fsf_status_qual.word[0]) {
1988 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
1989 zfcp_test_link(unit->port);
1990 /* fall through */
1991 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1992 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1993 break;
1994 }
1995 break;
1996 case FSF_GOOD:
1997 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
1998 break;
1999 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002000}
2001
2002/**
2003 * zfcp_fsf_close_unit - close zfcp unit
2004 * @erp_action: pointer to struct zfcp_unit
2005 * Returns: 0 on success, error otherwise
2006 */
2007int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
2008{
Swen Schillig44cc76f2008-10-01 12:42:16 +02002009 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002010 struct zfcp_adapter *adapter = erp_action->adapter;
2011 struct zfcp_fsf_req *req;
2012 int retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Christof Schmitt04062892008-10-01 12:42:20 +02002014 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002015 if (zfcp_fsf_req_sbal_get(adapter))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 goto out;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002017 req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
2018 ZFCP_REQ_AUTO_CLEANUP,
2019 adapter->pool.fsf_req_erp);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002020 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002021 retval = PTR_ERR(req);
2022 goto out;
2023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002025 sbale = zfcp_qdio_sbale_req(req);
2026 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2028
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002029 req->qtcb->header.port_handle = erp_action->port->handle;
2030 req->qtcb->header.lun_handle = erp_action->unit->handle;
2031 req->handler = zfcp_fsf_close_unit_handler;
2032 req->data = erp_action->unit;
2033 req->erp_action = erp_action;
2034 erp_action->fsf_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
Christof Schmitt287ac012008-07-02 10:56:40 +02002036 zfcp_fsf_start_erp_timer(req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002037 retval = zfcp_fsf_req_send(req);
2038 if (retval) {
2039 zfcp_fsf_req_free(req);
2040 erp_action->fsf_req = NULL;
2041 }
2042out:
Christof Schmitt04062892008-10-01 12:42:20 +02002043 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002044 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045}
2046
Christof Schmittc9615852008-05-06 11:00:05 +02002047static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
2048{
2049 lat_rec->sum += lat;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002050 lat_rec->min = min(lat_rec->min, lat);
2051 lat_rec->max = max(lat_rec->max, lat);
Christof Schmittc9615852008-05-06 11:00:05 +02002052}
2053
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002054static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
Christof Schmittc9615852008-05-06 11:00:05 +02002055{
2056 struct fsf_qual_latency_info *lat_inf;
2057 struct latency_cont *lat;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002058 struct zfcp_unit *unit = req->unit;
Christof Schmittc9615852008-05-06 11:00:05 +02002059
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002060 lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
Christof Schmittc9615852008-05-06 11:00:05 +02002061
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002062 switch (req->qtcb->bottom.io.data_direction) {
Christof Schmittc9615852008-05-06 11:00:05 +02002063 case FSF_DATADIR_READ:
2064 lat = &unit->latencies.read;
2065 break;
2066 case FSF_DATADIR_WRITE:
2067 lat = &unit->latencies.write;
2068 break;
2069 case FSF_DATADIR_CMND:
2070 lat = &unit->latencies.cmd;
2071 break;
2072 default:
2073 return;
2074 }
2075
Christof Schmitt49f0f012009-03-02 13:08:57 +01002076 spin_lock(&unit->latencies.lock);
Christof Schmittc9615852008-05-06 11:00:05 +02002077 zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
2078 zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
2079 lat->counter++;
Christof Schmitt49f0f012009-03-02 13:08:57 +01002080 spin_unlock(&unit->latencies.lock);
Christof Schmittc9615852008-05-06 11:00:05 +02002081}
2082
Stefan Raspl0997f1c2008-10-16 08:23:39 +02002083#ifdef CONFIG_BLK_DEV_IO_TRACE
2084static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
2085{
2086 struct fsf_qual_latency_info *lat_inf;
2087 struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
2088 struct request *req = scsi_cmnd->request;
2089 struct zfcp_blk_drv_data trace;
2090 int ticks = fsf_req->adapter->timer_ticks;
2091
2092 trace.flags = 0;
2093 trace.magic = ZFCP_BLK_DRV_DATA_MAGIC;
2094 if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
2095 trace.flags |= ZFCP_BLK_LAT_VALID;
2096 lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
2097 trace.channel_lat = lat_inf->channel_lat * ticks;
2098 trace.fabric_lat = lat_inf->fabric_lat * ticks;
2099 }
2100 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
2101 trace.flags |= ZFCP_BLK_REQ_ERROR;
2102 trace.inb_usage = fsf_req->qdio_inb_usage;
2103 trace.outb_usage = fsf_req->qdio_outb_usage;
2104
2105 blk_add_driver_data(req->q, req, &trace, sizeof(trace));
2106}
2107#else
2108static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req)
2109{
2110}
2111#endif
2112
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002113static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114{
Swen Schillig0ac55aa2008-11-26 18:07:39 +01002115 struct scsi_cmnd *scpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002117 &(req->qtcb->bottom.io.fcp_rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 u32 sns_len;
Martin Petermannf76af7d2008-07-02 10:56:36 +02002119 char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002122 read_lock_irqsave(&req->adapter->abort_lock, flags);
2123
Swen Schillig0ac55aa2008-11-26 18:07:39 +01002124 scpnt = req->data;
2125 if (unlikely(!scpnt)) {
2126 read_unlock_irqrestore(&req->adapter->abort_lock, flags);
2127 return;
2128 }
2129
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002130 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
Martin Petermannfeac6a02008-07-02 10:56:35 +02002131 set_host_byte(scpnt, DID_SOFT_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 goto skip_fsfstatus;
2133 }
2134
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002135 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
Martin Petermannfeac6a02008-07-02 10:56:35 +02002136 set_host_byte(scpnt, DID_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 goto skip_fsfstatus;
2138 }
2139
Martin Petermannfeac6a02008-07-02 10:56:35 +02002140 set_msg_byte(scpnt, COMMAND_COMPLETE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 scpnt->result |= fcp_rsp_iu->scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002144 if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
2145 zfcp_fsf_req_latency(req);
Christof Schmittc9615852008-05-06 11:00:05 +02002146
Stefan Raspl0997f1c2008-10-16 08:23:39 +02002147 zfcp_fsf_trace_latency(req);
2148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002150 if (fcp_rsp_info[3] == RSP_CODE_GOOD)
Martin Petermannfeac6a02008-07-02 10:56:35 +02002151 set_host_byte(scpnt, DID_OK);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002152 else {
Martin Petermannfeac6a02008-07-02 10:56:35 +02002153 set_host_byte(scpnt, DID_ERROR);
6f71d9b2005-04-10 23:04:28 -05002154 goto skip_fsfstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 }
2156 }
2157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002159 sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) +
2160 fcp_rsp_iu->fcp_rsp_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
FUJITA Tomonori9d058ec2008-01-27 12:41:50 +09002164 memcpy(scpnt->sense_buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 }
2167
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
FUJITA Tomonori7936a892007-07-29 16:46:28 +09002169 scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
2170 if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
2171 scpnt->underflow)
Martin Petermannfeac6a02008-07-02 10:56:35 +02002172 set_host_byte(scpnt, DID_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002174skip_fsfstatus:
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02002175 if (scpnt->result != 0)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002176 zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02002177 else if (scpnt->retries > 0)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002178 zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02002179 else
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002180 zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 scpnt->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 (scpnt->scsi_done) (scpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 /*
2185 * We must hold this lock until scsi_done has been called.
2186 * Otherwise we may call scsi_done after abort regarding this
2187 * command has completed.
2188 * Note: scsi_done must not block!
2189 */
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002190 read_unlock_irqrestore(&req->adapter->abort_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191}
2192
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002193static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002196 &(req->qtcb->bottom.io.fcp_rsp);
Martin Petermannf76af7d2008-07-02 10:56:36 +02002197 char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002199 if ((fcp_rsp_info[3] != RSP_CODE_GOOD) ||
2200 (req->status & ZFCP_STATUS_FSFREQ_ERROR))
2201 req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202}
2203
2204
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002205static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
2206{
2207 struct zfcp_unit *unit;
2208 struct fsf_qtcb_header *header = &req->qtcb->header;
2209
2210 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
2211 unit = req->data;
2212 else
2213 unit = req->unit;
2214
2215 if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR))
2216 goto skip_fsfstatus;
2217
2218 switch (header->fsf_status) {
2219 case FSF_HANDLE_MISMATCH:
2220 case FSF_PORT_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002221 zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002222 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2223 break;
2224 case FSF_FCPLUN_NOT_VALID:
2225 case FSF_LUN_HANDLE_NOT_VALID:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002226 zfcp_erp_port_reopen(unit->port, 0, "fssfch2", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002227 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2228 break;
2229 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
2230 zfcp_fsf_class_not_supp(req);
2231 break;
2232 case FSF_ACCESS_DENIED:
2233 zfcp_fsf_access_denied_unit(req, unit);
2234 break;
2235 case FSF_DIRECTION_INDICATOR_NOT_VALID:
2236 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02002237 "Incorrect direction %d, unit 0x%016Lx on port "
2238 "0x%016Lx closed\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002239 req->qtcb->bottom.io.data_direction,
Swen Schillig7ba58c92008-10-01 12:42:18 +02002240 (unsigned long long)unit->fcp_lun,
2241 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002242 zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3",
2243 req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002244 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2245 break;
2246 case FSF_CMND_LENGTH_NOT_VALID:
2247 dev_err(&req->adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02002248 "Incorrect CDB length %d, unit 0x%016Lx on "
2249 "port 0x%016Lx closed\n",
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002250 req->qtcb->bottom.io.fcp_cmnd_length,
Swen Schillig7ba58c92008-10-01 12:42:18 +02002251 (unsigned long long)unit->fcp_lun,
2252 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002253 zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4",
2254 req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002255 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2256 break;
2257 case FSF_PORT_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002258 zfcp_erp_port_boxed(unit->port, "fssfch5", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002259 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2260 ZFCP_STATUS_FSFREQ_RETRY;
2261 break;
2262 case FSF_LUN_BOXED:
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002263 zfcp_erp_unit_boxed(unit, "fssfch6", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002264 req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2265 ZFCP_STATUS_FSFREQ_RETRY;
2266 break;
2267 case FSF_ADAPTER_STATUS_AVAILABLE:
2268 if (header->fsf_status_qual.word[0] ==
2269 FSF_SQ_INVOKE_LINK_TEST_PROCEDURE)
2270 zfcp_test_link(unit->port);
2271 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2272 break;
2273 }
2274skip_fsfstatus:
2275 if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
2276 zfcp_fsf_send_fcp_ctm_handler(req);
2277 else {
2278 zfcp_fsf_send_fcp_command_task_handler(req);
2279 req->unit = NULL;
2280 zfcp_unit_put(unit);
2281 }
2282}
2283
Swen Schillig7ba58c92008-10-01 12:42:18 +02002284static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
2285{
2286 u32 *fcp_dl_ptr;
2287
2288 /*
2289 * fcp_dl_addr = start address of fcp_cmnd structure +
2290 * size of fixed part + size of dynamically sized add_dcp_cdb field
2291 * SEE FCP-2 documentation
2292 */
2293 fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
2294 (fcp_cmd->add_fcp_cdb_length << 2));
2295 *fcp_dl_ptr = fcp_dl;
2296}
2297
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002298/**
2299 * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002300 * @unit: unit where command is sent to
2301 * @scsi_cmnd: scsi command to be sent
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002302 */
Christof Schmitt63caf362009-03-02 13:09:00 +01002303int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
2304 struct scsi_cmnd *scsi_cmnd)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002305{
2306 struct zfcp_fsf_req *req;
2307 struct fcp_cmnd_iu *fcp_cmnd_iu;
2308 unsigned int sbtype;
2309 int real_bytes, retval = -EIO;
Christof Schmitt63caf362009-03-02 13:09:00 +01002310 struct zfcp_adapter *adapter = unit->port->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002311
2312 if (unlikely(!(atomic_read(&unit->status) &
2313 ZFCP_STATUS_COMMON_UNBLOCKED)))
2314 return -EBUSY;
2315
Christof Schmitt04062892008-10-01 12:42:20 +02002316 spin_lock(&adapter->req_q_lock);
Christof Schmitt8fdf30d2009-03-02 13:09:01 +01002317 if (atomic_read(&adapter->req_q.count) <= 0) {
2318 atomic_inc(&adapter->qdio_outb_full);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002319 goto out;
Christof Schmitt8fdf30d2009-03-02 13:09:01 +01002320 }
Christof Schmitt63caf362009-03-02 13:09:00 +01002321 req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND,
2322 ZFCP_REQ_AUTO_CLEANUP,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002323 adapter->pool.fsf_req_scsi);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002324 if (IS_ERR(req)) {
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002325 retval = PTR_ERR(req);
2326 goto out;
2327 }
2328
2329 zfcp_unit_get(unit);
2330 req->unit = unit;
2331 req->data = scsi_cmnd;
2332 req->handler = zfcp_fsf_send_fcp_command_handler;
2333 req->qtcb->header.lun_handle = unit->handle;
2334 req->qtcb->header.port_handle = unit->port->handle;
2335 req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2336
2337 scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2338
2339 fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd);
2340 fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2341 /*
2342 * set depending on data direction:
2343 * data direction bits in SBALE (SB Type)
2344 * data direction bits in QTCB
2345 * data direction bits in FCP_CMND IU
2346 */
2347 switch (scsi_cmnd->sc_data_direction) {
2348 case DMA_NONE:
2349 req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2350 sbtype = SBAL_FLAGS0_TYPE_READ;
2351 break;
2352 case DMA_FROM_DEVICE:
2353 req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2354 sbtype = SBAL_FLAGS0_TYPE_READ;
2355 fcp_cmnd_iu->rddata = 1;
2356 break;
2357 case DMA_TO_DEVICE:
2358 req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2359 sbtype = SBAL_FLAGS0_TYPE_WRITE;
2360 fcp_cmnd_iu->wddata = 1;
2361 break;
2362 case DMA_BIDIRECTIONAL:
2363 default:
2364 retval = -EIO;
2365 goto failed_scsi_cmnd;
2366 }
2367
2368 if (likely((scsi_cmnd->device->simple_tags) ||
2369 ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) &&
2370 (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED))))
2371 fcp_cmnd_iu->task_attribute = SIMPLE_Q;
2372 else
2373 fcp_cmnd_iu->task_attribute = UNTAGGED;
2374
2375 if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
2376 fcp_cmnd_iu->add_fcp_cdb_length =
2377 (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
2378
2379 memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
2380
2381 req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
Swen Schillig7ba58c92008-10-01 12:42:18 +02002382 fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002383
2384 real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
2385 scsi_sglist(scsi_cmnd),
2386 FSF_MAX_SBALS_PER_REQ);
2387 if (unlikely(real_bytes < 0)) {
2388 if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
2389 retval = -EIO;
2390 else {
2391 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02002392 "Oversize data package, unit 0x%016Lx "
2393 "on port 0x%016Lx closed\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02002394 (unsigned long long)unit->fcp_lun,
2395 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01002396 zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002397 retval = -EINVAL;
2398 }
2399 goto failed_scsi_cmnd;
2400 }
2401
2402 zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
2403
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002404 retval = zfcp_fsf_req_send(req);
2405 if (unlikely(retval))
2406 goto failed_scsi_cmnd;
2407
2408 goto out;
2409
2410failed_scsi_cmnd:
2411 zfcp_unit_put(unit);
2412 zfcp_fsf_req_free(req);
2413 scsi_cmnd->host_scribble = NULL;
2414out:
Christof Schmitt04062892008-10-01 12:42:20 +02002415 spin_unlock(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002416 return retval;
2417}
2418
2419/**
2420 * zfcp_fsf_send_fcp_ctm - send SCSI task management command
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002421 * @unit: pointer to struct zfcp_unit
2422 * @tm_flags: unsigned byte for task management flags
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002423 * Returns: on success pointer to struct fsf_req, NULL otherwise
2424 */
Christof Schmitt63caf362009-03-02 13:09:00 +01002425struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002426{
Swen Schillig44cc76f2008-10-01 12:42:16 +02002427 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002428 struct zfcp_fsf_req *req = NULL;
2429 struct fcp_cmnd_iu *fcp_cmnd_iu;
Christof Schmitt63caf362009-03-02 13:09:00 +01002430 struct zfcp_adapter *adapter = unit->port->adapter;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002431
2432 if (unlikely(!(atomic_read(&unit->status) &
2433 ZFCP_STATUS_COMMON_UNBLOCKED)))
2434 return NULL;
2435
Christof Schmitt92cab0d2009-03-02 13:08:59 +01002436 spin_lock_bh(&adapter->req_q_lock);
2437 if (zfcp_fsf_req_sbal_get(adapter))
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002438 goto out;
Christof Schmitt63caf362009-03-02 13:09:00 +01002439 req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0,
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002440 adapter->pool.fsf_req_scsi);
Swen Schillig633528c2008-11-26 18:07:37 +01002441 if (IS_ERR(req)) {
2442 req = NULL;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002443 goto out;
Swen Schillig633528c2008-11-26 18:07:37 +01002444 }
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002445
2446 req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2447 req->data = unit;
2448 req->handler = zfcp_fsf_send_fcp_command_handler;
2449 req->qtcb->header.lun_handle = unit->handle;
2450 req->qtcb->header.port_handle = unit->port->handle;
2451 req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2452 req->qtcb->bottom.io.service_class = FSF_CLASS_3;
2453 req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
Swen Schillig7ba58c92008-10-01 12:42:18 +02002454 sizeof(u32);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002455
2456 sbale = zfcp_qdio_sbale_req(req);
2457 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2458 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2459
2460 fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd;
2461 fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2462 fcp_cmnd_iu->task_management_flags = tm_flags;
2463
2464 zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
2465 if (!zfcp_fsf_req_send(req))
2466 goto out;
2467
2468 zfcp_fsf_req_free(req);
2469 req = NULL;
2470out:
Christof Schmitt92cab0d2009-03-02 13:08:59 +01002471 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002472 return req;
2473}
2474
2475static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
2476{
2477 if (req->qtcb->header.fsf_status != FSF_GOOD)
2478 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2479}
2480
2481/**
2482 * zfcp_fsf_control_file - control file upload/download
2483 * @adapter: pointer to struct zfcp_adapter
2484 * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc
2485 * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 */
Christof Schmitt45633fd2008-06-10 18:20:55 +02002487struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2488 struct zfcp_fsf_cfdc *fsf_cfdc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489{
Swen Schillig44cc76f2008-10-01 12:42:16 +02002490 struct qdio_buffer_element *sbale;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002491 struct zfcp_fsf_req *req = NULL;
2492 struct fsf_qtcb_bottom_support *bottom;
2493 int direction, retval = -EIO, bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
Christof Schmitt45633fd2008-06-10 18:20:55 +02002495 if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
2496 return ERR_PTR(-EOPNOTSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
Christof Schmitt45633fd2008-06-10 18:20:55 +02002498 switch (fsf_cfdc->command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
2500 direction = SBAL_FLAGS0_TYPE_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 case FSF_QTCB_UPLOAD_CONTROL_FILE:
2503 direction = SBAL_FLAGS0_TYPE_READ;
2504 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 default:
Christof Schmitt45633fd2008-06-10 18:20:55 +02002506 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 }
2508
Christof Schmitt04062892008-10-01 12:42:20 +02002509 spin_lock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002510 if (zfcp_fsf_req_sbal_get(adapter))
2511 goto out;
2512
2513 req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL);
Hirofumi Nakagawa025270f2008-08-21 13:43:37 +02002514 if (IS_ERR(req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 retval = -EPERM;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002516 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 }
2518
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002519 req->handler = zfcp_fsf_control_file_handler;
2520
2521 sbale = zfcp_qdio_sbale_req(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 sbale[0].flags |= direction;
2523
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002524 bottom = &req->qtcb->bottom.support;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
Christof Schmitt45633fd2008-06-10 18:20:55 +02002526 bottom->option = fsf_cfdc->option;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002528 bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
2529 FSF_MAX_SBALS_PER_REQ);
Christof Schmitt45633fd2008-06-10 18:20:55 +02002530 if (bytes != ZFCP_CFDC_MAX_SIZE) {
2531 retval = -ENOMEM;
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002532 zfcp_fsf_req_free(req);
2533 goto out;
Christof Schmitt45633fd2008-06-10 18:20:55 +02002534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002536 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2537 retval = zfcp_fsf_req_send(req);
2538out:
Christof Schmitt04062892008-10-01 12:42:20 +02002539 spin_unlock_bh(&adapter->req_q_lock);
Swen Schilligc41f8cb2008-07-02 10:56:39 +02002540
2541 if (!retval) {
2542 wait_event(req->completion_wq,
2543 req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
2544 return req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
Christof Schmitt45633fd2008-06-10 18:20:55 +02002546 return ERR_PTR(retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547}