blob: 01ed5fb46c441d9dd88abade746b7847b7f8a704 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include "zfcp_ext.h"
10
11static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *);
12static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *);
13static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *);
14static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *);
15static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *);
16static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *);
17static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *);
18static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *);
19static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *);
20static int zfcp_fsf_send_fcp_command_task_management_handler(
21 struct zfcp_fsf_req *);
22static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);
23static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
24static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
25static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
Christof Schmitt45633fd2008-06-10 18:20:55 +020026static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070027static inline int zfcp_fsf_req_sbal_check(
28 unsigned long *, struct zfcp_qdio_queue *, int);
29static inline int zfcp_use_one_sbal(
30 struct scatterlist *, int, struct scatterlist *, int);
31static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
Andreas Herrmann2abbe862006-09-18 22:29:56 +020032static int zfcp_fsf_req_send(struct zfcp_fsf_req *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070033static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
34static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
35static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
Martin Peschke698ec0162008-03-27 14:22:02 +010036static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *, u8,
Maxim Shchetyninaef4a982005-09-13 21:51:16 +020037 struct fsf_link_down_info *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* association between FSF command and FSF QTCB type */
41static u32 fsf_qtcb_type[] = {
42 [FSF_QTCB_FCP_CMND] = FSF_IO_COMMAND,
43 [FSF_QTCB_ABORT_FCP_CMND] = FSF_SUPPORT_COMMAND,
44 [FSF_QTCB_OPEN_PORT_WITH_DID] = FSF_SUPPORT_COMMAND,
45 [FSF_QTCB_OPEN_LUN] = FSF_SUPPORT_COMMAND,
46 [FSF_QTCB_CLOSE_LUN] = FSF_SUPPORT_COMMAND,
47 [FSF_QTCB_CLOSE_PORT] = FSF_SUPPORT_COMMAND,
48 [FSF_QTCB_CLOSE_PHYSICAL_PORT] = FSF_SUPPORT_COMMAND,
49 [FSF_QTCB_SEND_ELS] = FSF_SUPPORT_COMMAND,
50 [FSF_QTCB_SEND_GENERIC] = FSF_SUPPORT_COMMAND,
51 [FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,
52 [FSF_QTCB_EXCHANGE_PORT_DATA] = FSF_PORT_COMMAND,
53 [FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,
54 [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
55};
56
57static const char zfcp_act_subtable_type[5][8] = {
58 "unknown", "OS", "WWPN", "DID", "LUN"
59};
60
Christof Schmitt553448f2008-06-10 18:20:58 +020061static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
62{
63 u16 subtable = (table & 0xffff0000) >> 16;
64 u16 rule = table & 0xffff;
65
66 if (subtable > 0 &&
67 subtable < ARRAY_SIZE(zfcp_act_subtable_type)) {
68 dev_warn(&adapter->ccw_device->dev,
69 "Access denied in subtable %s, rule %d.\n",
70 zfcp_act_subtable_type[subtable], rule);
71 }
72}
73
74static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
75 struct zfcp_port *port)
76{
77 struct fsf_qtcb_header *header = &req->qtcb->header;
78 dev_warn(&req->adapter->ccw_device->dev,
79 "Access denied, cannot send command to port 0x%016Lx.\n",
80 port->wwpn);
81 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
82 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
83 zfcp_erp_port_access_denied(port, 55, req);
84 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
85}
86
87static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
88 struct zfcp_unit *unit)
89{
90 struct fsf_qtcb_header *header = &req->qtcb->header;
91 dev_warn(&req->adapter->ccw_device->dev,
92 "Access denied for unit 0x%016Lx on port 0x%016Lx.\n",
93 unit->fcp_lun, unit->port->wwpn);
94 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
95 zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
96 zfcp_erp_unit_access_denied(unit, 59, req);
97 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
98}
99
100static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
101{
102 dev_err(&req->adapter->ccw_device->dev,
103 "Required FC class not supported by adapter, "
104 "shutting down adapter.\n");
105 zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req);
106 req->status |= ZFCP_STATUS_FSFREQ_ERROR;
107}
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/****************************************************************/
110/*************** FSF related Functions *************************/
111/****************************************************************/
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*
114 * function: zfcp_fsf_req_alloc
115 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200116 * purpose: Obtains an fsf_req and potentially a qtcb (for all but
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 * unsolicited requests) via helper functions
118 * Does some initial fsf request set-up.
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200119 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 * returns: pointer to allocated fsf_req if successfull
121 * NULL otherwise
122 *
123 * locks: none
124 *
125 */
126static struct zfcp_fsf_req *
127zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
128{
129 size_t size;
130 void *ptr;
131 struct zfcp_fsf_req *fsf_req = NULL;
132
133 if (req_flags & ZFCP_REQ_NO_QTCB)
134 size = sizeof(struct zfcp_fsf_req);
135 else
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200136 size = sizeof(struct zfcp_fsf_req_qtcb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200138 if (likely(pool))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 ptr = mempool_alloc(pool, GFP_ATOMIC);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200140 else {
141 if (req_flags & ZFCP_REQ_NO_QTCB)
142 ptr = kmalloc(size, GFP_ATOMIC);
143 else
144 ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
Christoph Lameter54e6ecb2006-12-06 20:33:16 -0800145 GFP_ATOMIC);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200148 if (unlikely(!ptr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 goto out;
150
151 memset(ptr, 0, size);
152
153 if (req_flags & ZFCP_REQ_NO_QTCB) {
154 fsf_req = (struct zfcp_fsf_req *) ptr;
155 } else {
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200156 fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req;
157 fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
159
160 fsf_req->pool = pool;
161
162 out:
163 return fsf_req;
164}
165
166/*
167 * function: zfcp_fsf_req_free
168 *
169 * purpose: Frees the memory of an fsf_req (and potentially a qtcb) or
170 * returns it into the pool via helper functions.
171 *
172 * returns: sod all
173 *
174 * locks: none
175 */
Andreas Herrmann1db2c9c2005-06-13 13:20:35 +0200176void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
178{
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200179 if (likely(fsf_req->pool)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 mempool_free(fsf_req, fsf_req->pool);
Heiko Carstensdd52e0e2006-09-18 22:28:49 +0200181 return;
182 }
183
184 if (fsf_req->qtcb) {
185 kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req);
186 return;
187 }
188
189 kfree(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190}
191
Martin Peschke869b2b42007-05-09 11:01:20 +0200192/*
193 * Never ever call this without shutting down the adapter first.
194 * Otherwise the adapter would continue using and corrupting s390 storage.
195 * Included BUG_ON() call to ensure this is done.
196 * ERP is supposed to be the only user of this function.
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200197 */
Swen Schillig6fcc4712007-02-07 13:17:57 +0100198void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200199{
Martin Peschke869b2b42007-05-09 11:01:20 +0200200 struct zfcp_fsf_req *fsf_req, *tmp;
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200201 unsigned long flags;
Swen Schillig6fcc4712007-02-07 13:17:57 +0100202 LIST_HEAD(remove_queue);
Martin Peschke869b2b42007-05-09 11:01:20 +0200203 unsigned int i;
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200204
Martin Peschke869b2b42007-05-09 11:01:20 +0200205 BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status));
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200206 spin_lock_irqsave(&adapter->req_list_lock, flags);
Martin Peschke869b2b42007-05-09 11:01:20 +0200207 for (i = 0; i < REQUEST_LIST_SIZE; i++)
Swen Schillig6fcc4712007-02-07 13:17:57 +0100208 list_splice_init(&adapter->req_list[i], &remove_queue);
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200209 spin_unlock_irqrestore(&adapter->req_list_lock, flags);
210
Martin Peschke869b2b42007-05-09 11:01:20 +0200211 list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) {
212 list_del(&fsf_req->list);
213 fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
214 zfcp_fsf_req_complete(fsf_req);
Swen Schillig6fcc4712007-02-07 13:17:57 +0100215 }
Volker Sameskefea9d6c2006-08-02 11:05:16 +0200216}
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218/*
219 * function: zfcp_fsf_req_complete
220 *
221 * purpose: Updates active counts and timers for openfcp-reqs
222 * May cleanup request after req_eval returns
223 *
224 * returns: 0 - success
225 * !0 - failure
226 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200227 * context:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 */
229int
230zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
231{
232 int retval = 0;
233 int cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 /*
237 * Note: all cleanup handling is done in the callchain of
238 * the function call-chain below.
239 */
240 zfcp_fsf_status_read_handler(fsf_req);
241 goto out;
Andreas Herrmann2abbe862006-09-18 22:29:56 +0200242 } else {
243 del_timer(&fsf_req->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 zfcp_fsf_protstatus_eval(fsf_req);
Andreas Herrmann2abbe862006-09-18 22:29:56 +0200245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 /*
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200248 * fsf_req may be deleted due to waking up functions, so
249 * cleanup is saved here and used later
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 */
251 if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
252 cleanup = 1;
253 else
254 cleanup = 0;
255
256 fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;
257
258 /* cleanup request if requested by initiator */
259 if (likely(cleanup)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 /*
261 * lock must not be held here since it will be
262 * grabed by the called routine, too
263 */
Andreas Herrmann1db2c9c2005-06-13 13:20:35 +0200264 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 } else {
266 /* notify initiator waiting for the requests completion */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 /*
268 * FIXME: Race! We must not access fsf_req here as it might have been
269 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
270 * flag. It's an improbable case. But, we have the same paranoia for
271 * the cleanup flag already.
272 * Might better be handled using complete()?
273 * (setting the flag and doing wakeup ought to be atomic
274 * with regard to checking the flag as long as waitqueue is
275 * part of the to be released structure)
276 */
277 wake_up(&fsf_req->completion_wq);
278 }
279
280 out:
281 return retval;
282}
283
284/*
285 * function: zfcp_fsf_protstatus_eval
286 *
287 * purpose: evaluates the QTCB of the finished FSF request
288 * and initiates appropriate actions
289 * (usually calling FSF command specific handlers)
290 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200291 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200293 * context:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 *
295 * locks:
296 */
297static int
298zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
299{
300 int retval = 0;
301 struct zfcp_adapter *adapter = fsf_req->adapter;
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200302 struct fsf_qtcb *qtcb = fsf_req->qtcb;
303 union fsf_prot_status_qual *prot_status_qual =
304 &qtcb->prefix.prot_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200306 zfcp_hba_dbf_event_fsf_response(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
310 ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 goto skip_protstatus;
312 }
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 /* evaluate FSF Protocol Status */
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200315 switch (qtcb->prefix.prot_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 case FSF_PROT_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 case FSF_PROT_FSF_STATUS_PRESENTED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 break;
320
321 case FSF_PROT_QTCB_VERSION_ERROR:
Christof Schmitt553448f2008-06-10 18:20:58 +0200322 dev_err(&adapter->ccw_device->dev,
323 "The QTCB version requested by zfcp (0x%x) is not "
324 "supported by the FCP adapter (lowest supported 0x%x, "
325 "highest supported 0x%x).\n",
326 ZFCP_QTCB_VERSION, prot_status_qual->word[0],
327 prot_status_qual->word[1]);
Martin Peschke1f6f7122008-04-18 12:51:55 +0200328 zfcp_erp_adapter_shutdown(adapter, 0, 117, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
330 break;
331
332 case FSF_PROT_SEQ_NUMB_ERROR:
Martin Peschke1f6f7122008-04-18 12:51:55 +0200333 zfcp_erp_adapter_reopen(adapter, 0, 98, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
335 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
336 break;
337
338 case FSF_PROT_UNSUPP_QTCB_TYPE:
Christof Schmitt553448f2008-06-10 18:20:58 +0200339 dev_err(&adapter->ccw_device->dev,
340 "Packet header type used by the device driver is "
341 "incompatible with that used on the adapter.\n");
Martin Peschke1f6f7122008-04-18 12:51:55 +0200342 zfcp_erp_adapter_shutdown(adapter, 0, 118, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
344 break;
345
346 case FSF_PROT_HOST_CONNECTION_INITIALIZING:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
348 atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
349 &(adapter->status));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 break;
351
352 case FSF_PROT_DUPLICATE_REQUEST_ID:
Christof Schmitt553448f2008-06-10 18:20:58 +0200353 dev_err(&adapter->ccw_device->dev,
354 "The request identifier 0x%Lx is ambiguous.\n",
355 (unsigned long long)qtcb->bottom.support.req_handle);
Martin Peschke1f6f7122008-04-18 12:51:55 +0200356 zfcp_erp_adapter_shutdown(adapter, 0, 78, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
358 break;
359
360 case FSF_PROT_LINK_DOWN:
Martin Peschke698ec0162008-03-27 14:22:02 +0100361 zfcp_fsf_link_down_info_eval(fsf_req, 37,
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200362 &prot_status_qual->link_down_info);
Martin Peschke9467a9b2008-03-27 14:22:03 +0100363 /* FIXME: reopening adapter now? better wait for link up */
Martin Peschke1f6f7122008-04-18 12:51:55 +0200364 zfcp_erp_adapter_reopen(adapter, 0, 79, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
366 break;
367
368 case FSF_PROT_REEST_QUEUE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 /* All ports should be marked as ready to run again */
Martin Peschke1f6f7122008-04-18 12:51:55 +0200370 zfcp_erp_modify_adapter_status(adapter, 28, NULL,
371 ZFCP_STATUS_COMMON_RUNNING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 ZFCP_SET);
373 zfcp_erp_adapter_reopen(adapter,
374 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
Martin Peschke9467a9b2008-03-27 14:22:03 +0100375 | ZFCP_STATUS_COMMON_ERP_FAILED,
Martin Peschke1f6f7122008-04-18 12:51:55 +0200376 99, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
378 break;
379
380 case FSF_PROT_ERROR_STATE:
Martin Peschke1f6f7122008-04-18 12:51:55 +0200381 zfcp_erp_adapter_reopen(adapter, 0, 100, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;
383 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
384 break;
385
386 default:
Christof Schmitt553448f2008-06-10 18:20:58 +0200387 dev_err(&adapter->ccw_device->dev,
388 "Transfer protocol status information"
389 "provided by the adapter (0x%x) "
390 "is not compatible with the device driver.\n",
391 qtcb->prefix.prot_status);
Martin Peschke1f6f7122008-04-18 12:51:55 +0200392 zfcp_erp_adapter_shutdown(adapter, 0, 119, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
394 }
395
396 skip_protstatus:
397 /*
398 * always call specific handlers to give them a chance to do
399 * something meaningful even in error cases
400 */
401 zfcp_fsf_fsfstatus_eval(fsf_req);
402 return retval;
403}
404
405/*
406 * function: zfcp_fsf_fsfstatus_eval
407 *
408 * purpose: evaluates FSF status of completed FSF request
409 * and acts accordingly
410 *
411 * returns:
412 */
413static int
414zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req)
415{
416 int retval = 0;
417
418 if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
419 goto skip_fsfstatus;
420 }
421
422 /* evaluate FSF Status */
423 switch (fsf_req->qtcb->header.fsf_status) {
424 case FSF_UNKNOWN_COMMAND:
Christof Schmitt553448f2008-06-10 18:20:58 +0200425 dev_err(&fsf_req->adapter->ccw_device->dev,
426 "Command issued by the device driver (0x%x) is "
427 "not known by the adapter.\n",
428 fsf_req->qtcb->header.fsf_command);
Martin Peschke1f6f7122008-04-18 12:51:55 +0200429 zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 120, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
431 break;
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 zfcp_fsf_fsfstatus_qual_eval(fsf_req);
435 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
437
438 skip_fsfstatus:
439 /*
440 * always call specific handlers to give them a chance to do
441 * something meaningful even in error cases
442 */
443 zfcp_fsf_req_dispatch(fsf_req);
444
445 return retval;
446}
447
448/*
449 * function: zfcp_fsf_fsfstatus_qual_eval
450 *
451 * purpose: evaluates FSF status-qualifier of completed FSF request
452 * and acts accordingly
453 *
454 * returns:
455 */
456static int
457zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
458{
459 int retval = 0;
460
461 switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
462 case FSF_SQ_FCP_RSP_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 break;
464 case FSF_SQ_RETRY_IF_POSSIBLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 /* The SCSI-stack may now issue retries or escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
467 break;
468 case FSF_SQ_COMMAND_ABORTED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 /* Carry the aborted state on to upper layer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED;
471 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
472 break;
473 case FSF_SQ_NO_RECOM:
Christof Schmitt553448f2008-06-10 18:20:58 +0200474 dev_err(&fsf_req->adapter->ccw_device->dev,
475 "No recommendation could be given for a "
476 "problem on the adapter.\n");
Martin Peschke1f6f7122008-04-18 12:51:55 +0200477 zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 121, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
479 break;
480 case FSF_SQ_ULP_PROGRAMMING_ERROR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
482 break;
483 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
484 case FSF_SQ_NO_RETRY_POSSIBLE:
485 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
486 /* dealt with in the respective functions */
487 break;
488 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
490 break;
491 }
492
493 return retval;
494}
495
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200496/**
497 * zfcp_fsf_link_down_info_eval - evaluate link down information block
498 */
499static void
Martin Peschke698ec0162008-03-27 14:22:02 +0100500zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *fsf_req, u8 id,
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200501 struct fsf_link_down_info *link_down)
502{
Martin Peschke698ec0162008-03-27 14:22:02 +0100503 struct zfcp_adapter *adapter = fsf_req->adapter;
504
Maxim Shchetyninee69ab72005-12-01 02:48:41 +0100505 if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
506 &adapter->status))
507 return;
508
509 atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
510
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100511 if (link_down == NULL)
512 goto out;
Maxim Shchetyninee69ab72005-12-01 02:48:41 +0100513
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200514 switch (link_down->error_code) {
515 case FSF_PSQ_LINK_NO_LIGHT:
Christof Schmitt553448f2008-06-10 18:20:58 +0200516 dev_warn(&fsf_req->adapter->ccw_device->dev,
517 "The local link is down: "
518 "no light detected.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200519 break;
520 case FSF_PSQ_LINK_WRAP_PLUG:
Christof Schmitt553448f2008-06-10 18:20:58 +0200521 dev_warn(&fsf_req->adapter->ccw_device->dev,
522 "The local link is down: "
523 "wrap plug detected.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200524 break;
525 case FSF_PSQ_LINK_NO_FCP:
Christof Schmitt553448f2008-06-10 18:20:58 +0200526 dev_warn(&fsf_req->adapter->ccw_device->dev,
527 "The local link is down: "
528 "adjacent node on link does not support FCP.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200529 break;
530 case FSF_PSQ_LINK_FIRMWARE_UPDATE:
Christof Schmitt553448f2008-06-10 18:20:58 +0200531 dev_warn(&fsf_req->adapter->ccw_device->dev,
532 "The local link is down: "
533 "firmware update in progress.\n");
534 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200535 case FSF_PSQ_LINK_INVALID_WWPN:
Christof Schmitt553448f2008-06-10 18:20:58 +0200536 dev_warn(&fsf_req->adapter->ccw_device->dev,
537 "The local link is down: "
538 "duplicate or invalid WWPN detected.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200539 break;
540 case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
Christof Schmitt553448f2008-06-10 18:20:58 +0200541 dev_warn(&fsf_req->adapter->ccw_device->dev,
542 "The local link is down: "
543 "no support for NPIV by Fabric.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200544 break;
545 case FSF_PSQ_LINK_NO_FCP_RESOURCES:
Christof Schmitt553448f2008-06-10 18:20:58 +0200546 dev_warn(&fsf_req->adapter->ccw_device->dev,
547 "The local link is down: "
548 "out of resource in FCP daughtercard.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200549 break;
550 case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
Christof Schmitt553448f2008-06-10 18:20:58 +0200551 dev_warn(&fsf_req->adapter->ccw_device->dev,
552 "The local link is down: "
553 "out of resource in Fabric.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200554 break;
555 case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
Christof Schmitt553448f2008-06-10 18:20:58 +0200556 dev_warn(&fsf_req->adapter->ccw_device->dev,
557 "The local link is down: "
558 "unable to login to Fabric.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200559 break;
560 case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
Christof Schmitt553448f2008-06-10 18:20:58 +0200561 dev_warn(&fsf_req->adapter->ccw_device->dev,
562 "WWPN assignment file corrupted on adapter.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200563 break;
564 case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
Christof Schmitt553448f2008-06-10 18:20:58 +0200565 dev_warn(&fsf_req->adapter->ccw_device->dev,
566 "Mode table corrupted on adapter.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200567 break;
568 case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
Christof Schmitt553448f2008-06-10 18:20:58 +0200569 dev_warn(&fsf_req->adapter->ccw_device->dev,
570 "No WWPN for assignment table on adapter.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200571 break;
572 default:
Christof Schmitt553448f2008-06-10 18:20:58 +0200573 dev_warn(&fsf_req->adapter->ccw_device->dev,
574 "The local link to adapter is down.\n");
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200575 }
576
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +0100577 out:
Martin Peschke1f6f7122008-04-18 12:51:55 +0200578 zfcp_erp_adapter_failed(adapter, id, fsf_req);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200579}
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581/*
582 * function: zfcp_fsf_req_dispatch
583 *
584 * purpose: calls the appropriate command specific handler
585 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200586 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 */
588static int
589zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
590{
591 struct zfcp_erp_action *erp_action = fsf_req->erp_action;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 int retval = 0;
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 switch (fsf_req->fsf_command) {
596
597 case FSF_QTCB_FCP_CMND:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 zfcp_fsf_send_fcp_command_handler(fsf_req);
599 break;
600
601 case FSF_QTCB_ABORT_FCP_CMND:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 zfcp_fsf_abort_fcp_command_handler(fsf_req);
603 break;
604
605 case FSF_QTCB_SEND_GENERIC:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 zfcp_fsf_send_ct_handler(fsf_req);
607 break;
608
609 case FSF_QTCB_OPEN_PORT_WITH_DID:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 zfcp_fsf_open_port_handler(fsf_req);
611 break;
612
613 case FSF_QTCB_OPEN_LUN:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 zfcp_fsf_open_unit_handler(fsf_req);
615 break;
616
617 case FSF_QTCB_CLOSE_LUN:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 zfcp_fsf_close_unit_handler(fsf_req);
619 break;
620
621 case FSF_QTCB_CLOSE_PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 zfcp_fsf_close_port_handler(fsf_req);
623 break;
624
625 case FSF_QTCB_CLOSE_PHYSICAL_PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 zfcp_fsf_close_physical_port_handler(fsf_req);
627 break;
628
629 case FSF_QTCB_EXCHANGE_CONFIG_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 zfcp_fsf_exchange_config_data_handler(fsf_req);
631 break;
632
633 case FSF_QTCB_EXCHANGE_PORT_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 zfcp_fsf_exchange_port_data_handler(fsf_req);
635 break;
636
637 case FSF_QTCB_SEND_ELS:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 zfcp_fsf_send_els_handler(fsf_req);
639 break;
640
641 case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 zfcp_fsf_control_file_handler(fsf_req);
643 break;
644
645 case FSF_QTCB_UPLOAD_CONTROL_FILE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 zfcp_fsf_control_file_handler(fsf_req);
647 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
649
650 if (!erp_action)
651 return retval;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 zfcp_erp_async_handler(erp_action, 0);
654
655 return retval;
656}
657
658/*
659 * function: zfcp_fsf_status_read
660 *
661 * purpose: initiates a Status Read command at the specified adapter
662 *
663 * returns:
664 */
665int
666zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
667{
668 struct zfcp_fsf_req *fsf_req;
669 struct fsf_status_read_buffer *status_buffer;
670 unsigned long lock_flags;
671 volatile struct qdio_buffer_element *sbale;
Heiko Carstensb2141782008-05-19 12:17:39 +0200672 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 /* setup new FSF request */
675 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
676 req_flags | ZFCP_REQ_NO_QTCB,
677 adapter->pool.fsf_req_status_read,
678 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +0200679 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 goto failed_req_create;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Swen Schillig00bab912008-06-10 18:20:57 +0200682 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS;
684 sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
685 fsf_req->sbale_curr = 2;
686
Heiko Carstensb2141782008-05-19 12:17:39 +0200687 retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 status_buffer =
689 mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC);
Heiko Carstensb2141782008-05-19 12:17:39 +0200690 if (!status_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 goto failed_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer));
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200693 fsf_req->data = (unsigned long) status_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 /* insert pointer to respective buffer */
696 sbale = zfcp_qdio_sbale_curr(fsf_req);
697 sbale->addr = (void *) status_buffer;
698 sbale->length = sizeof(struct fsf_status_read_buffer);
699
Andreas Herrmann2abbe862006-09-18 22:29:56 +0200700 retval = zfcp_fsf_req_send(fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +0200701 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 goto failed_req_send;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 goto out;
705
706 failed_req_send:
707 mempool_free(status_buffer, adapter->pool.data_status_read);
708
709 failed_buf:
710 zfcp_fsf_req_free(fsf_req);
711 failed_req_create:
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200712 zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 out:
Swen Schillig00bab912008-06-10 18:20:57 +0200714 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return retval;
716}
717
718static int
719zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
720{
721 struct fsf_status_read_buffer *status_buffer;
722 struct zfcp_adapter *adapter;
723 struct zfcp_port *port;
724 unsigned long flags;
725
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200726 status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 adapter = fsf_req->adapter;
728
729 read_lock_irqsave(&zfcp_data.config_lock, flags);
730 list_for_each_entry(port, &adapter->port_list_head, list)
731 if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK))
732 break;
733 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
734
Christof Schmitt553448f2008-06-10 18:20:58 +0200735 if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 switch (status_buffer->status_subtype) {
739
740 case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT:
Martin Peschke1f6f7122008-04-18 12:51:55 +0200741 zfcp_erp_port_reopen(port, 0, 101, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 break;
743
744 case FSF_STATUS_READ_SUB_ERROR_PORT:
Martin Peschke1f6f7122008-04-18 12:51:55 +0200745 zfcp_erp_port_shutdown(port, 0, 122, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 }
748 out:
749 return 0;
750}
751
Christof Schmitt553448f2008-06-10 18:20:58 +0200752static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req)
753{
754 struct zfcp_adapter *adapter = req->adapter;
755 struct fsf_status_read_buffer *buf =
756 (struct fsf_status_read_buffer *) req->data;
757 struct fsf_bit_error_payload *err =
758 (struct fsf_bit_error_payload *) buf->payload;
759 dev_warn(&adapter->ccw_device->dev,
760 "Warning: bit error threshold data "
761 "received for the adapter: "
762 "link failures = %i, loss of sync errors = %i, "
763 "loss of signal errors = %i, "
764 "primitive sequence errors = %i, "
765 "invalid transmission word errors = %i, "
766 "CRC errors = %i).\n",
767 err->link_failure_error_count,
768 err->loss_of_sync_error_count,
769 err->loss_of_signal_error_count,
770 err->primitive_sequence_error_count,
771 err->invalid_transmission_word_error_count,
772 err->crc_error_count);
773 dev_warn(&adapter->ccw_device->dev,
774 "Additional bit error threshold data of the adapter: "
775 "primitive sequence event time-outs = %i, "
776 "elastic buffer overrun errors = %i, "
777 "advertised receive buffer-to-buffer credit = %i, "
778 "current receice buffer-to-buffer credit = %i, "
779 "advertised transmit buffer-to-buffer credit = %i, "
780 "current transmit buffer-to-buffer credit = %i).\n",
781 err->primitive_sequence_event_timeout_count,
782 err->elastic_buffer_overrun_error_count,
783 err->advertised_receive_b2b_credit,
784 err->current_receive_b2b_credit,
785 err->advertised_transmit_b2b_credit,
786 err->current_transmit_b2b_credit);
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789/*
790 * function: zfcp_fsf_status_read_handler
791 *
792 * purpose: is called for finished Open Port command
793 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200794 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 */
796static int
797zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
798{
799 int retval = 0;
800 struct zfcp_adapter *adapter = fsf_req->adapter;
801 struct fsf_status_read_buffer *status_buffer =
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200802 (struct fsf_status_read_buffer *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200805 zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 mempool_free(status_buffer, adapter->pool.data_status_read);
Andreas Herrmann1db2c9c2005-06-13 13:20:35 +0200807 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 goto out;
809 }
810
Maxim Shchetynin8a36e452005-09-13 21:50:38 +0200811 zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer);
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 switch (status_buffer->status_type) {
814
815 case FSF_STATUS_READ_PORT_CLOSED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 zfcp_fsf_status_read_port_closed(fsf_req);
817 break;
818
819 case FSF_STATUS_READ_INCOMING_ELS:
Christof Schmitt24073b42008-06-10 18:20:54 +0200820 zfcp_fc_incoming_els(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 break;
822
823 case FSF_STATUS_READ_SENSE_DATA_AVAIL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 break;
825
826 case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
Christof Schmitt553448f2008-06-10 18:20:58 +0200827 zfcp_fsf_bit_error_threshold(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 break;
829
830 case FSF_STATUS_READ_LINK_DOWN:
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200831 switch (status_buffer->status_subtype) {
832 case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
Christof Schmitt553448f2008-06-10 18:20:58 +0200833 dev_warn(&adapter->ccw_device->dev,
834 "Physical link is down.\n");
Martin Peschke698ec0162008-03-27 14:22:02 +0100835 zfcp_fsf_link_down_info_eval(fsf_req, 38,
Maxim Shchetyninee69ab72005-12-01 02:48:41 +0100836 (struct fsf_link_down_info *)
837 &status_buffer->payload);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200838 break;
839 case FSF_STATUS_READ_SUB_FDISC_FAILED:
Christof Schmitt553448f2008-06-10 18:20:58 +0200840 dev_warn(&adapter->ccw_device->dev,
841 "Local link is down "
842 "due to failed FDISC login.\n");
Martin Peschke698ec0162008-03-27 14:22:02 +0100843 zfcp_fsf_link_down_info_eval(fsf_req, 39,
Maxim Shchetyninee69ab72005-12-01 02:48:41 +0100844 (struct fsf_link_down_info *)
845 &status_buffer->payload);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200846 break;
847 case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
Christof Schmitt553448f2008-06-10 18:20:58 +0200848 dev_warn(&adapter->ccw_device->dev,
849 "Local link is down "
850 "due to firmware update on adapter.\n");
Martin Peschke698ec0162008-03-27 14:22:02 +0100851 zfcp_fsf_link_down_info_eval(fsf_req, 40, NULL);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200852 break;
853 default:
Christof Schmitt553448f2008-06-10 18:20:58 +0200854 dev_warn(&adapter->ccw_device->dev,
855 "Local link is down.\n");
Martin Peschke698ec0162008-03-27 14:22:02 +0100856 zfcp_fsf_link_down_info_eval(fsf_req, 41, NULL);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200857 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 break;
859
860 case FSF_STATUS_READ_LINK_UP:
Christof Schmitt553448f2008-06-10 18:20:58 +0200861 dev_info(&adapter->ccw_device->dev,
862 "Local link was replugged.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 /* All ports should be marked as ready to run again */
Martin Peschke1f6f7122008-04-18 12:51:55 +0200864 zfcp_erp_modify_adapter_status(adapter, 30, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 ZFCP_STATUS_COMMON_RUNNING,
866 ZFCP_SET);
867 zfcp_erp_adapter_reopen(adapter,
868 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
Martin Peschke9467a9b2008-03-27 14:22:03 +0100869 | ZFCP_STATUS_COMMON_ERP_FAILED,
Martin Peschke1f6f7122008-04-18 12:51:55 +0200870 102, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 break;
872
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100873 case FSF_STATUS_READ_NOTIFICATION_LOST:
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100874 if (status_buffer->status_subtype &
875 FSF_STATUS_READ_SUB_ACT_UPDATED)
Martin Peschke1f6f7122008-04-18 12:51:55 +0200876 zfcp_erp_adapter_access_changed(adapter, 135, fsf_req);
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +0100877 break;
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 case FSF_STATUS_READ_CFDC_UPDATED:
Martin Peschke1f6f7122008-04-18 12:51:55 +0200880 zfcp_erp_adapter_access_changed(adapter, 136, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 break;
882
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200883 case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
Maxim Shchetyninaef4a982005-09-13 21:51:16 +0200884 adapter->adapter_features = *(u32*) status_buffer->payload;
885 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 }
887 mempool_free(status_buffer, adapter->pool.data_status_read);
Andreas Herrmann1db2c9c2005-06-13 13:20:35 +0200888 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /*
890 * recycle buffer and start new request repeat until outbound
891 * queue is empty or adapter shutdown is requested
892 */
893 /*
894 * FIXME(qdio):
895 * we may wait in the req_create for 5s during shutdown, so
896 * qdio_cleanup will have to wait at least that long before returning
897 * with failure to allow us a proper cleanup under all circumstances
898 */
899 /*
900 * FIXME:
901 * allocation failure possible? (Is this code needed?)
902 */
Swen Schilligd26ab062008-05-19 12:17:37 +0200903
904 atomic_inc(&adapter->stat_miss);
905 schedule_work(&adapter->stat_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 out:
907 return retval;
908}
909
910/*
911 * function: zfcp_fsf_abort_fcp_command
912 *
913 * purpose: tells FSF to abort a running SCSI command
914 *
915 * returns: address of initiated FSF request
916 * NULL - request could not be initiated
917 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200918 * FIXME(design): should be watched by a timeout !!!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 * FIXME(design) shouldn't this be modified to return an int
920 * also...don't know how though
921 */
922struct zfcp_fsf_req *
923zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
924 struct zfcp_adapter *adapter,
925 struct zfcp_unit *unit, int req_flags)
926{
927 volatile struct qdio_buffer_element *sbale;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 struct zfcp_fsf_req *fsf_req = NULL;
Andreas Herrmann2abbe862006-09-18 22:29:56 +0200929 unsigned long lock_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 int retval = 0;
931
932 /* setup new FSF request */
933 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
934 req_flags, adapter->pool.fsf_req_abort,
935 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +0200936 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Christof Schmitt951f7462007-12-20 12:30:24 +0100939 if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
940 &unit->status)))
941 goto unit_blocked;
942
Swen Schillig00bab912008-06-10 18:20:57 +0200943 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
945 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
946
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200947 fsf_req->data = (unsigned long) unit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 /* set handles of unit and its parent port in QTCB */
950 fsf_req->qtcb->header.lun_handle = unit->handle;
951 fsf_req->qtcb->header.port_handle = unit->port->handle;
952
953 /* set handle of request which should be aborted */
954 fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
955
Andreas Herrmann2abbe862006-09-18 22:29:56 +0200956 zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
957 retval = zfcp_fsf_req_send(fsf_req);
Christof Schmitt951f7462007-12-20 12:30:24 +0100958 if (!retval)
959 goto out;
960
961 unit_blocked:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 zfcp_fsf_req_free(fsf_req);
963 fsf_req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 out:
Swen Schillig00bab912008-06-10 18:20:57 +0200966 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return fsf_req;
968}
969
970/*
971 * function: zfcp_fsf_abort_fcp_command_handler
972 *
973 * purpose: is called for finished Abort FCP Command request
974 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +0200975 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 */
977static int
978zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
979{
980 int retval = -EINVAL;
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200981 struct zfcp_unit *unit;
Christof Schmitt86275332007-12-20 12:30:23 +0100982 union fsf_status_qual *fsf_stat_qual =
983 &new_fsf_req->qtcb->header.fsf_status_qual;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
986 /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
987 goto skip_fsfstatus;
988 }
989
Andreas Herrmann059c97d2005-09-13 21:47:52 +0200990 unit = (struct zfcp_unit *) new_fsf_req->data;
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* evaluate FSF status in QTCB */
993 switch (new_fsf_req->qtcb->header.fsf_status) {
994
995 case FSF_PORT_HANDLE_NOT_VALID:
Christof Schmitt86275332007-12-20 12:30:23 +0100996 if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 /*
998 * In this case a command that was sent prior to a port
999 * reopen was aborted (handles are different). This is
1000 * fine.
1001 */
1002 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 /* Let's hope this sorts out the mess */
Martin Peschke9467a9b2008-03-27 14:22:03 +01001004 zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104,
Martin Peschke1f6f7122008-04-18 12:51:55 +02001005 new_fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1007 }
1008 break;
1009
1010 case FSF_LUN_HANDLE_NOT_VALID:
Christof Schmitt86275332007-12-20 12:30:23 +01001011 if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 /*
1013 * In this case a command that was sent prior to a unit
1014 * reopen was aborted (handles are different).
1015 * This is fine.
1016 */
1017 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 /* Let's hope this sorts out the mess */
Martin Peschke1f6f7122008-04-18 12:51:55 +02001019 zfcp_erp_port_reopen(unit->port, 0, 105, new_fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1021 }
1022 break;
1023
1024 case FSF_FCP_COMMAND_DOES_NOT_EXIST:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
1027 break;
1028
1029 case FSF_PORT_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02001030 zfcp_erp_port_boxed(unit->port, 47, new_fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
1032 | ZFCP_STATUS_FSFREQ_RETRY;
1033 break;
1034
1035 case FSF_LUN_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02001036 zfcp_erp_unit_boxed(unit, 48, new_fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
1038 | ZFCP_STATUS_FSFREQ_RETRY;
1039 break;
1040
1041 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) {
1043 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Andreas Herrmann65a8d4e2005-06-13 13:16:27 +02001044 zfcp_test_link(unit->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1046 break;
1047 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 /* SCSI stack will escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1050 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052 break;
1053
1054 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 retval = 0;
1056 new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED;
1057 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059 skip_fsfstatus:
1060 return retval;
1061}
1062
1063/**
1064 * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
1065 * one SBALE
1066 * Two scatter-gather lists are passed, one for the reqeust and one for the
1067 * response.
1068 */
1069static inline int
1070zfcp_use_one_sbal(struct scatterlist *req, int req_count,
1071 struct scatterlist *resp, int resp_count)
1072{
1073 return ((req_count == 1) &&
1074 (resp_count == 1) &&
1075 (((unsigned long) zfcp_sg_to_address(&req[0]) &
1076 PAGE_MASK) ==
1077 ((unsigned long) (zfcp_sg_to_address(&req[0]) +
1078 req[0].length - 1) & PAGE_MASK)) &&
1079 (((unsigned long) zfcp_sg_to_address(&resp[0]) &
1080 PAGE_MASK) ==
1081 ((unsigned long) (zfcp_sg_to_address(&resp[0]) +
1082 resp[0].length - 1) & PAGE_MASK)));
1083}
1084
1085/**
1086 * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS)
1087 * @ct: pointer to struct zfcp_send_ct which conatins all needed data for
1088 * the request
1089 * @pool: pointer to memory pool, if non-null this pool is used to allocate
1090 * a struct zfcp_fsf_req
1091 * @erp_action: pointer to erp_action, if non-null the Generic Service request
1092 * is sent within error recovery
1093 */
1094int
1095zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
1096 struct zfcp_erp_action *erp_action)
1097{
1098 volatile struct qdio_buffer_element *sbale;
1099 struct zfcp_port *port;
1100 struct zfcp_adapter *adapter;
1101 struct zfcp_fsf_req *fsf_req;
1102 unsigned long lock_flags;
1103 int bytes;
1104 int ret = 0;
1105
1106 port = ct->port;
1107 adapter = port->adapter;
1108
1109 ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
1110 ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
1111 pool, &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02001112 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 goto failed_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Swen Schillig00bab912008-06-10 18:20:57 +02001115 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 if (zfcp_use_one_sbal(ct->req, ct->req_count,
1117 ct->resp, ct->resp_count)){
1118 /* both request buffer and response buffer
1119 fit into one sbale each */
1120 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
1121 sbale[2].addr = zfcp_sg_to_address(&ct->req[0]);
1122 sbale[2].length = ct->req[0].length;
1123 sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]);
1124 sbale[3].length = ct->resp[0].length;
1125 sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001126 } else if (adapter->adapter_features &
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
1128 /* try to use chained SBALs */
1129 bytes = zfcp_qdio_sbals_from_sg(fsf_req,
1130 SBAL_FLAGS0_TYPE_WRITE_READ,
Swen Schillig00bab912008-06-10 18:20:57 +02001131 ct->req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 ZFCP_MAX_SBALS_PER_CT_REQ);
1133 if (bytes <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 if (bytes == 0)
1135 ret = -ENOMEM;
1136 else
1137 ret = bytes;
1138
1139 goto failed_send;
1140 }
1141 fsf_req->qtcb->bottom.support.req_buf_length = bytes;
1142 fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
1143 bytes = zfcp_qdio_sbals_from_sg(fsf_req,
1144 SBAL_FLAGS0_TYPE_WRITE_READ,
Swen Schillig00bab912008-06-10 18:20:57 +02001145 ct->resp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 ZFCP_MAX_SBALS_PER_CT_REQ);
1147 if (bytes <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 if (bytes == 0)
1149 ret = -ENOMEM;
1150 else
1151 ret = bytes;
1152
1153 goto failed_send;
1154 }
1155 fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
1156 } else {
1157 /* reject send generic request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 ret = -EOPNOTSUPP;
1159 goto failed_send;
1160 }
1161
1162 /* settings in QTCB */
1163 fsf_req->qtcb->header.port_handle = port->handle;
Andreas Herrmann06506d02006-05-22 18:18:19 +02001164 fsf_req->qtcb->bottom.support.service_class =
1165 ZFCP_FC_SERVICE_CLASS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 fsf_req->qtcb->bottom.support.timeout = ct->timeout;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001167 fsf_req->data = (unsigned long) ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02001169 zfcp_san_dbf_event_ct_request(fsf_req);
1170
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001171 if (erp_action) {
1172 erp_action->fsf_req = fsf_req;
1173 fsf_req->erp_action = erp_action;
1174 zfcp_erp_start_timer(fsf_req);
1175 } else
1176 zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
1177
1178 ret = zfcp_fsf_req_send(fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02001179 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 goto failed_send;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 goto out;
1183
1184 failed_send:
1185 zfcp_fsf_req_free(fsf_req);
1186 if (erp_action != NULL) {
1187 erp_action->fsf_req = NULL;
1188 }
1189 failed_req:
1190 out:
Swen Schillig00bab912008-06-10 18:20:57 +02001191 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return ret;
1193}
1194
1195/**
1196 * zfcp_fsf_send_ct_handler - handler for Generic Service requests
1197 * @fsf_req: pointer to struct zfcp_fsf_req
1198 *
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001199 * Data specific for the Generic Service request is passed using
1200 * fsf_req->data. There we find the pointer to struct zfcp_send_ct.
1201 * Usually a specific handler for the CT request is called which is
1202 * found in this structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 */
1204static int
1205zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
1206{
1207 struct zfcp_port *port;
1208 struct zfcp_adapter *adapter;
1209 struct zfcp_send_ct *send_ct;
1210 struct fsf_qtcb_header *header;
1211 struct fsf_qtcb_bottom_support *bottom;
1212 int retval = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 adapter = fsf_req->adapter;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001215 send_ct = (struct zfcp_send_ct *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 port = send_ct->port;
1217 header = &fsf_req->qtcb->header;
1218 bottom = &fsf_req->qtcb->bottom.support;
1219
1220 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
1221 goto skip_fsfstatus;
1222
1223 /* evaluate FSF status in QTCB */
1224 switch (header->fsf_status) {
1225
1226 case FSF_GOOD:
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02001227 zfcp_san_dbf_event_ct_response(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 retval = 0;
1229 break;
1230
1231 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
Christof Schmitt553448f2008-06-10 18:20:58 +02001232 zfcp_fsf_class_not_supp(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 break;
1234
1235 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 switch (header->fsf_status_qual.word[0]){
1237 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 /* reopening link to port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 zfcp_test_link(port);
1240 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1241 break;
1242 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 /* ERP strategy will escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1245 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 }
1247 break;
1248
1249 case FSF_ACCESS_DENIED:
Christof Schmitt553448f2008-06-10 18:20:58 +02001250 zfcp_fsf_access_denied_port(fsf_req, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 break;
1252
1253 case FSF_GENERIC_COMMAND_REJECTED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1255 break;
1256
1257 case FSF_PORT_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02001258 zfcp_erp_adapter_reopen(adapter, 0, 106, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1260 break;
1261
1262 case FSF_PORT_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02001263 zfcp_erp_port_boxed(port, 49, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
1265 | ZFCP_STATUS_FSFREQ_RETRY;
1266 break;
1267
1268 /* following states should never occure, all cases avoided
1269 in zfcp_fsf_send_ct - but who knows ... */
1270 case FSF_PAYLOAD_SIZE_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 case FSF_REQUEST_SIZE_TOO_LARGE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 case FSF_RESPONSE_SIZE_TOO_LARGE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 case FSF_SBAL_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1275 break;
1276
1277 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 break;
1279 }
1280
1281skip_fsfstatus:
1282 send_ct->status = retval;
1283
1284 if (send_ct->handler != NULL)
1285 send_ct->handler(send_ct->handler_data);
1286
1287 return retval;
1288}
1289
1290/**
1291 * zfcp_fsf_send_els - initiate an ELS command (FC-FS)
1292 * @els: pointer to struct zfcp_send_els which contains all needed data for
1293 * the command.
1294 */
1295int
1296zfcp_fsf_send_els(struct zfcp_send_els *els)
1297{
1298 volatile struct qdio_buffer_element *sbale;
1299 struct zfcp_fsf_req *fsf_req;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +02001300 u32 d_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 struct zfcp_adapter *adapter;
1302 unsigned long lock_flags;
1303 int bytes;
1304 int ret = 0;
1305
1306 d_id = els->d_id;
1307 adapter = els->adapter;
1308
1309 ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
1310 ZFCP_REQ_AUTO_CLEANUP,
1311 NULL, &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02001312 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 goto failed_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Christof Schmitt3f0ca622007-12-20 12:30:25 +01001315 if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
1316 &els->port->status))) {
1317 ret = -EBUSY;
1318 goto port_blocked;
1319 }
1320
Swen Schillig00bab912008-06-10 18:20:57 +02001321 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (zfcp_use_one_sbal(els->req, els->req_count,
1323 els->resp, els->resp_count)){
1324 /* both request buffer and response buffer
1325 fit into one sbale each */
1326 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
1327 sbale[2].addr = zfcp_sg_to_address(&els->req[0]);
1328 sbale[2].length = els->req[0].length;
1329 sbale[3].addr = zfcp_sg_to_address(&els->resp[0]);
1330 sbale[3].length = els->resp[0].length;
1331 sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001332 } else if (adapter->adapter_features &
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 FSF_FEATURE_ELS_CT_CHAINED_SBALS) {
1334 /* try to use chained SBALs */
1335 bytes = zfcp_qdio_sbals_from_sg(fsf_req,
1336 SBAL_FLAGS0_TYPE_WRITE_READ,
Swen Schillig00bab912008-06-10 18:20:57 +02001337 els->req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 ZFCP_MAX_SBALS_PER_ELS_REQ);
1339 if (bytes <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (bytes == 0) {
1341 ret = -ENOMEM;
1342 } else {
1343 ret = bytes;
1344 }
1345 goto failed_send;
1346 }
1347 fsf_req->qtcb->bottom.support.req_buf_length = bytes;
1348 fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
1349 bytes = zfcp_qdio_sbals_from_sg(fsf_req,
1350 SBAL_FLAGS0_TYPE_WRITE_READ,
Swen Schillig00bab912008-06-10 18:20:57 +02001351 els->resp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 ZFCP_MAX_SBALS_PER_ELS_REQ);
1353 if (bytes <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (bytes == 0) {
1355 ret = -ENOMEM;
1356 } else {
1357 ret = bytes;
1358 }
1359 goto failed_send;
1360 }
1361 fsf_req->qtcb->bottom.support.resp_buf_length = bytes;
1362 } else {
1363 /* reject request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 ret = -EOPNOTSUPP;
1365 goto failed_send;
1366 }
1367
1368 /* settings in QTCB */
1369 fsf_req->qtcb->bottom.support.d_id = d_id;
Andreas Herrmann06506d02006-05-22 18:18:19 +02001370 fsf_req->qtcb->bottom.support.service_class =
1371 ZFCP_FC_SERVICE_CLASS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001373 fsf_req->data = (unsigned long) els;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Swen Schillig00bab912008-06-10 18:20:57 +02001375 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02001377 zfcp_san_dbf_event_els_request(fsf_req);
1378
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001379 zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
1380 ret = zfcp_fsf_req_send(fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02001381 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 goto failed_send;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 goto out;
1385
Christof Schmitt3f0ca622007-12-20 12:30:25 +01001386 port_blocked:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 failed_send:
1388 zfcp_fsf_req_free(fsf_req);
1389
1390 failed_req:
1391 out:
Swen Schillig00bab912008-06-10 18:20:57 +02001392 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 return ret;
1395}
1396
1397/**
1398 * zfcp_fsf_send_els_handler - handler for ELS commands
1399 * @fsf_req: pointer to struct zfcp_fsf_req
1400 *
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001401 * Data specific for the ELS command is passed using
1402 * fsf_req->data. There we find the pointer to struct zfcp_send_els.
1403 * Usually a specific handler for the ELS command is called which is
1404 * found in this structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 */
1406static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
1407{
1408 struct zfcp_adapter *adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 struct zfcp_port *port;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +02001410 u32 d_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 struct fsf_qtcb_header *header;
1412 struct fsf_qtcb_bottom_support *bottom;
1413 struct zfcp_send_els *send_els;
1414 int retval = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001416 send_els = (struct zfcp_send_els *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 adapter = send_els->adapter;
Andreas Herrmann64b29a132005-06-13 13:18:56 +02001418 port = send_els->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 d_id = send_els->d_id;
1420 header = &fsf_req->qtcb->header;
1421 bottom = &fsf_req->qtcb->bottom.support;
1422
1423 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
1424 goto skip_fsfstatus;
1425
1426 switch (header->fsf_status) {
1427
1428 case FSF_GOOD:
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02001429 zfcp_san_dbf_event_els_response(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 retval = 0;
1431 break;
1432
1433 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
Christof Schmitt553448f2008-06-10 18:20:58 +02001434 zfcp_fsf_class_not_supp(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 break;
1436
1437 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 switch (header->fsf_status_qual.word[0]){
1439 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Andreas Herrmann64b29a132005-06-13 13:18:56 +02001440 if (port && (send_els->ls_code != ZFCP_LS_ADISC))
1441 zfcp_test_link(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1443 break;
1444 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 break;
1447 case FSF_SQ_RETRY_IF_POSSIBLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1449 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 }
1451 break;
1452
1453 case FSF_ELS_COMMAND_REJECTED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 case FSF_PAYLOAD_SIZE_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 case FSF_REQUEST_SIZE_TOO_LARGE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 case FSF_RESPONSE_SIZE_TOO_LARGE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 break;
1458
1459 case FSF_SBAL_MISMATCH:
1460 /* should never occure, avoided in zfcp_fsf_send_els */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1462 break;
1463
1464 case FSF_ACCESS_DENIED:
Christof Schmitt553448f2008-06-10 18:20:58 +02001465 zfcp_fsf_access_denied_port(fsf_req, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 break;
1467
1468 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1470 break;
1471 }
1472
1473skip_fsfstatus:
1474 send_els->status = retval;
1475
Heiko Carstensaa551da2007-07-18 10:55:10 +02001476 if (send_els->handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 send_els->handler(send_els->handler_data);
1478
1479 return retval;
1480}
1481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482int
1483zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
1484{
1485 volatile struct qdio_buffer_element *sbale;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001486 struct zfcp_fsf_req *fsf_req;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001487 struct zfcp_adapter *adapter = erp_action->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 unsigned long lock_flags;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001489 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491 /* setup new FSF request */
Swen Schillig52ef11a2007-08-28 09:31:09 +02001492 retval = zfcp_fsf_req_create(adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 FSF_QTCB_EXCHANGE_CONFIG_DATA,
1494 ZFCP_REQ_AUTO_CLEANUP,
Swen Schillig52ef11a2007-08-28 09:31:09 +02001495 adapter->pool.fsf_req_erp,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001496 &lock_flags, &fsf_req);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001497 if (retval) {
Swen Schillig00bab912008-06-10 18:20:57 +02001498 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001499 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 }
1501
Swen Schillig00bab912008-06-10 18:20:57 +02001502 sbale = zfcp_qdio_sbale_req(fsf_req);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001503 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1504 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001506 fsf_req->qtcb->bottom.config.feature_selection =
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001507 FSF_FEATURE_CFDC |
1508 FSF_FEATURE_LUN_SHARING |
Maxim Shchetynin9eb69af2006-01-05 09:56:47 +01001509 FSF_FEATURE_NOTIFICATION_LOST |
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001510 FSF_FEATURE_UPDATE_ALERT;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001511 fsf_req->erp_action = erp_action;
1512 erp_action->fsf_req = fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001514 zfcp_erp_start_timer(fsf_req);
1515 retval = zfcp_fsf_req_send(fsf_req);
Swen Schillig00bab912008-06-10 18:20:57 +02001516 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 if (retval) {
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001518 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 erp_action->fsf_req = NULL;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001520 }
Swen Schillig52ef11a2007-08-28 09:31:09 +02001521
1522 return retval;
1523}
1524
1525int
1526zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
1527 struct fsf_qtcb_bottom_config *data)
1528{
1529 volatile struct qdio_buffer_element *sbale;
1530 struct zfcp_fsf_req *fsf_req;
1531 unsigned long lock_flags;
1532 int retval;
1533
1534 /* setup new FSF request */
1535 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
Swen Schilligaee6ef12008-04-24 19:35:52 +02001536 ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags,
1537 &fsf_req);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001538 if (retval) {
Swen Schillig00bab912008-06-10 18:20:57 +02001539 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001540 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 }
1542
Swen Schillig00bab912008-06-10 18:20:57 +02001543 sbale = zfcp_qdio_sbale_req(fsf_req);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001544 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1545 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
Swen Schillig52ef11a2007-08-28 09:31:09 +02001547 fsf_req->qtcb->bottom.config.feature_selection =
1548 FSF_FEATURE_CFDC |
1549 FSF_FEATURE_LUN_SHARING |
1550 FSF_FEATURE_NOTIFICATION_LOST |
1551 FSF_FEATURE_UPDATE_ALERT;
1552
1553 if (data)
1554 fsf_req->data = (unsigned long) data;
1555
1556 zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
1557 retval = zfcp_fsf_req_send(fsf_req);
Swen Schillig00bab912008-06-10 18:20:57 +02001558 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Christof Schmitt553448f2008-06-10 18:20:58 +02001559 if (!retval)
Swen Schillig52ef11a2007-08-28 09:31:09 +02001560 wait_event(fsf_req->completion_wq,
1561 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
1562
1563 zfcp_fsf_req_free(fsf_req);
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 return retval;
1566}
1567
1568/**
1569 * zfcp_fsf_exchange_config_evaluate
1570 * @fsf_req: fsf_req which belongs to xchg config data request
1571 * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1)
1572 *
1573 * returns: -EIO on error, 0 otherwise
1574 */
1575static int
1576zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
1577{
1578 struct fsf_qtcb_bottom_config *bottom;
1579 struct zfcp_adapter *adapter = fsf_req->adapter;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +02001580 struct Scsi_Host *shost = adapter->scsi_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 bottom = &fsf_req->qtcb->bottom.config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 adapter->fsf_lic_version = bottom->lic_version;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001584 adapter->adapter_features = bottom->adapter_features;
1585 adapter->connection_features = bottom->connection_features;
6f71d9b2005-04-10 23:04:28 -05001586 adapter->peer_wwpn = 0;
1587 adapter->peer_wwnn = 0;
1588 adapter->peer_d_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 if (xchg_ok) {
Swen Schillig52ef11a2007-08-28 09:31:09 +02001591
1592 if (fsf_req->data)
1593 memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data,
1594 bottom, sizeof (struct fsf_qtcb_bottom_config));
1595
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +02001596 fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
1597 fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
1598 fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
1599 fc_host_speed(shost) = bottom->fc_link_speed;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001600 fc_host_supported_classes(shost) =
1601 FC_COS_CLASS2 | FC_COS_CLASS3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 adapter->hydra_version = bottom->adapter_type;
Christof Schmittc9615852008-05-06 11:00:05 +02001603 adapter->timer_ticks = bottom->timer_interval;
Andreas Herrmannad757cd2006-01-13 02:26:11 +01001604 if (fc_host_permanent_port_name(shost) == -1)
1605 fc_host_permanent_port_name(shost) =
1606 fc_host_port_name(shost);
1607 if (bottom->fc_topology == FSF_TOPO_P2P) {
1608 adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
1609 adapter->peer_wwpn = bottom->plogi_payload.wwpn;
1610 adapter->peer_wwnn = bottom->plogi_payload.wwnn;
1611 fc_host_port_type(shost) = FC_PORTTYPE_PTP;
1612 } else if (bottom->fc_topology == FSF_TOPO_FABRIC)
1613 fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
1614 else if (bottom->fc_topology == FSF_TOPO_AL)
1615 fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
1616 else
1617 fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 } else {
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +02001619 fc_host_node_name(shost) = 0;
1620 fc_host_port_name(shost) = 0;
1621 fc_host_port_id(shost) = 0;
1622 fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
Andreas Herrmannad757cd2006-01-13 02:26:11 +01001623 fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 adapter->hydra_version = 0;
1625 }
1626
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001627 if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 adapter->hardware_version = bottom->hardware_version;
Andreas Herrmann13e1e1f2005-09-19 16:56:17 +02001629 memcpy(fc_host_serial_number(shost), bottom->serial_number,
1630 min(FC_SERIAL_NUMBER_SIZE, 17));
1631 EBCASC(fc_host_serial_number(shost),
1632 min(FC_SERIAL_NUMBER_SIZE, 17));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 }
1634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +02001636 dev_err(&adapter->ccw_device->dev,
1637 "The adapter only supports newer control block "
1638 "versions, try updated device driver.\n");
Martin Peschke1f6f7122008-04-18 12:51:55 +02001639 zfcp_erp_adapter_shutdown(adapter, 0, 125, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 return -EIO;
1641 }
1642 if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) {
Christof Schmitt553448f2008-06-10 18:20:58 +02001643 dev_err(&adapter->ccw_device->dev,
1644 "The adapter only supports older control block "
1645 "versions, consider a microcode upgrade.\n");
Martin Peschke1f6f7122008-04-18 12:51:55 +02001646 zfcp_erp_adapter_shutdown(adapter, 0, 126, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 return -EIO;
1648 }
1649 return 0;
1650}
1651
Swen Schillig52ef11a2007-08-28 09:31:09 +02001652/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 * function: zfcp_fsf_exchange_config_data_handler
1654 *
1655 * purpose: is called for finished Exchange Configuration Data command
1656 *
1657 * returns:
1658 */
1659static int
1660zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
1661{
1662 struct fsf_qtcb_bottom_config *bottom;
1663 struct zfcp_adapter *adapter = fsf_req->adapter;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001664 struct fsf_qtcb *qtcb = fsf_req->qtcb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
1667 return -EIO;
1668
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001669 switch (qtcb->header.fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
1673 return -EIO;
1674
Andreas Herrmannad757cd2006-01-13 02:26:11 +01001675 switch (fc_host_port_type(adapter->scsi_host)) {
1676 case FC_PORTTYPE_PTP:
Christof Schmitt553448f2008-06-10 18:20:58 +02001677 if (fsf_req->erp_action)
1678 dev_info(&adapter->ccw_device->dev,
1679 "Point-to-Point fibrechannel "
1680 "configuration detected.\n");
6f71d9b2005-04-10 23:04:28 -05001681 break;
Andreas Herrmannad757cd2006-01-13 02:26:11 +01001682 case FC_PORTTYPE_NLPORT:
Christof Schmitt553448f2008-06-10 18:20:58 +02001683 dev_err(&adapter->ccw_device->dev,
1684 "Unsupported arbitrated loop fibrechannel "
1685 "topology detected, shutting down adapter\n");
Martin Peschke1f6f7122008-04-18 12:51:55 +02001686 zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return -EIO;
Andreas Herrmannad757cd2006-01-13 02:26:11 +01001688 case FC_PORTTYPE_NPORT:
Swen Schilligec258fe2008-04-24 19:35:53 +02001689 if (fsf_req->erp_action)
Christof Schmitt553448f2008-06-10 18:20:58 +02001690 dev_info(&adapter->ccw_device->dev,
1691 "Switched fabric fibrechannel "
1692 "network detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 break;
1694 default:
Christof Schmitt553448f2008-06-10 18:20:58 +02001695 dev_err(&adapter->ccw_device->dev,
1696 "The fibrechannel topology reported by the "
1697 "adapter is not known by the zfcp driver, "
1698 "shutting down adapter.\n");
Martin Peschke1f6f7122008-04-18 12:51:55 +02001699 zfcp_erp_adapter_shutdown(adapter, 0, 128, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 return -EIO;
1701 }
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001702 bottom = &qtcb->bottom.config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
Christof Schmitt553448f2008-06-10 18:20:58 +02001704 dev_err(&adapter->ccw_device->dev,
1705 "Maximum QTCB size (%d bytes) allowed by "
1706 "the adapter is lower than the minimum "
1707 "required by the driver (%ld bytes).\n",
1708 bottom->max_qtcb_size, sizeof(struct fsf_qtcb));
Martin Peschke1f6f7122008-04-18 12:51:55 +02001709 zfcp_erp_adapter_shutdown(adapter, 0, 129, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 return -EIO;
1711 }
1712 atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
1713 &adapter->status);
1714 break;
1715 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
1717 return -EIO;
1718
Swen Schillig52ef11a2007-08-28 09:31:09 +02001719 atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
1720 &adapter->status);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001721
Martin Peschke698ec0162008-03-27 14:22:02 +01001722 zfcp_fsf_link_down_info_eval(fsf_req, 42,
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001723 &qtcb->header.fsf_status_qual.link_down_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 break;
1725 default:
Martin Peschke1f6f7122008-04-18 12:51:55 +02001726 zfcp_erp_adapter_shutdown(adapter, 0, 130, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 return -EIO;
1728 }
1729 return 0;
1730}
1731
1732/**
1733 * zfcp_fsf_exchange_port_data - request information about local port
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001734 * @erp_action: ERP action for the adapter for which port data is requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 */
1736int
Swen Schillig52ef11a2007-08-28 09:31:09 +02001737zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738{
1739 volatile struct qdio_buffer_element *sbale;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001740 struct zfcp_fsf_req *fsf_req;
1741 struct zfcp_adapter *adapter = erp_action->adapter;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001742 unsigned long lock_flags;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001743 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
Christof Schmitt553448f2008-06-10 18:20:58 +02001745 if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
Swen Schillig52ef11a2007-08-28 09:31:09 +02001746 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 /* setup new FSF request */
1749 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
Swen Schillig52ef11a2007-08-28 09:31:09 +02001750 ZFCP_REQ_AUTO_CLEANUP,
1751 adapter->pool.fsf_req_erp,
1752 &lock_flags, &fsf_req);
1753 if (retval) {
Swen Schillig00bab912008-06-10 18:20:57 +02001754 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001755 return retval;
1756 }
1757
Swen Schillig00bab912008-06-10 18:20:57 +02001758 sbale = zfcp_qdio_sbale_req(fsf_req);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001759 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1760 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1761
1762 erp_action->fsf_req = fsf_req;
1763 fsf_req->erp_action = erp_action;
1764 zfcp_erp_start_timer(fsf_req);
1765
1766 retval = zfcp_fsf_req_send(fsf_req);
Swen Schillig00bab912008-06-10 18:20:57 +02001767 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001768
1769 if (retval) {
Swen Schillig52ef11a2007-08-28 09:31:09 +02001770 zfcp_fsf_req_free(fsf_req);
1771 erp_action->fsf_req = NULL;
1772 }
Swen Schillig52ef11a2007-08-28 09:31:09 +02001773 return retval;
1774}
1775
1776
1777/**
1778 * zfcp_fsf_exchange_port_data_sync - request information about local port
1779 * and wait until information is ready
1780 */
1781int
1782zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
1783 struct fsf_qtcb_bottom_port *data)
1784{
1785 volatile struct qdio_buffer_element *sbale;
1786 struct zfcp_fsf_req *fsf_req;
1787 unsigned long lock_flags;
1788 int retval;
1789
Christof Schmitt553448f2008-06-10 18:20:58 +02001790 if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
Swen Schillig52ef11a2007-08-28 09:31:09 +02001791 return -EOPNOTSUPP;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001792
1793 /* setup new FSF request */
1794 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
1795 0, NULL, &lock_flags, &fsf_req);
1796 if (retval) {
Swen Schillig00bab912008-06-10 18:20:57 +02001797 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Andreas Herrmann2448c452005-12-01 02:50:36 +01001798 return retval;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001799 }
1800
1801 if (data)
Andreas Herrmann2448c452005-12-01 02:50:36 +01001802 fsf_req->data = (unsigned long) data;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001803
Swen Schillig00bab912008-06-10 18:20:57 +02001804 sbale = zfcp_qdio_sbale_req(fsf_req);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001805 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1806 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Swen Schillig52ef11a2007-08-28 09:31:09 +02001808 zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001809 retval = zfcp_fsf_req_send(fsf_req);
Swen Schillig00bab912008-06-10 18:20:57 +02001810 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Christof Schmitt553448f2008-06-10 18:20:58 +02001812 if (!retval)
Andreas Herrmann2448c452005-12-01 02:50:36 +01001813 wait_event(fsf_req->completion_wq,
1814 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
Swen Schillig52ef11a2007-08-28 09:31:09 +02001815
1816 zfcp_fsf_req_free(fsf_req);
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 return retval;
1819}
1820
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001821/**
1822 * zfcp_fsf_exchange_port_evaluate
1823 * @fsf_req: fsf_req which belongs to xchg port data request
1824 * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1)
1825 */
1826static void
1827zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
1828{
1829 struct zfcp_adapter *adapter;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001830 struct fsf_qtcb_bottom_port *bottom;
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001831 struct Scsi_Host *shost;
1832
1833 adapter = fsf_req->adapter;
Swen Schillig52ef11a2007-08-28 09:31:09 +02001834 bottom = &fsf_req->qtcb->bottom.port;
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001835 shost = adapter->scsi_host;
1836
Swen Schillig52ef11a2007-08-28 09:31:09 +02001837 if (fsf_req->data)
1838 memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom,
1839 sizeof(struct fsf_qtcb_bottom_port));
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001840
1841 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1842 fc_host_permanent_port_name(shost) = bottom->wwpn;
1843 else
1844 fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
1845 fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
1846 fc_host_supported_speeds(shost) = bottom->supported_speed;
1847}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
1849/**
1850 * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request
1851 * @fsf_req: pointer to struct zfcp_fsf_req
1852 */
1853static void
1854zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
1855{
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001856 struct zfcp_adapter *adapter;
1857 struct fsf_qtcb *qtcb;
1858
1859 adapter = fsf_req->adapter;
1860 qtcb = fsf_req->qtcb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
1862 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
1863 return;
1864
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001865 switch (qtcb->header.fsf_status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 case FSF_GOOD:
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001867 zfcp_fsf_exchange_port_evaluate(fsf_req, 1);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001868 atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001869 break;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001870 case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
Andreas Herrmann2f8f3ed2006-02-11 01:41:50 +01001871 zfcp_fsf_exchange_port_evaluate(fsf_req, 0);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001872 atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
Martin Peschke698ec0162008-03-27 14:22:02 +01001873 zfcp_fsf_link_down_info_eval(fsf_req, 43,
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001874 &qtcb->header.fsf_status_qual.link_down_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
1877}
1878
1879
1880/*
1881 * function: zfcp_fsf_open_port
1882 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +02001883 * purpose:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 *
1885 * returns: address of initiated FSF request
Swen Schillig41fa2ad2007-09-07 09:15:31 +02001886 * NULL - request could not be initiated
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 */
1888int
1889zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
1890{
1891 volatile struct qdio_buffer_element *sbale;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001892 struct zfcp_fsf_req *fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 unsigned long lock_flags;
1894 int retval = 0;
1895
1896 /* setup new FSF request */
1897 retval = zfcp_fsf_req_create(erp_action->adapter,
1898 FSF_QTCB_OPEN_PORT_WITH_DID,
1899 ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
1900 erp_action->adapter->pool.fsf_req_erp,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001901 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02001902 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Swen Schillig00bab912008-06-10 18:20:57 +02001905 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
1907 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
1908
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001909 fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001911 fsf_req->data = (unsigned long) erp_action->port;
1912 fsf_req->erp_action = erp_action;
1913 erp_action->fsf_req = fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001915 zfcp_erp_start_timer(fsf_req);
1916 retval = zfcp_fsf_req_send(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (retval) {
Andreas Herrmann2abbe862006-09-18 22:29:56 +02001918 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 erp_action->fsf_req = NULL;
1920 goto out;
1921 }
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 out:
Swen Schillig00bab912008-06-10 18:20:57 +02001924 write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return retval;
1926}
1927
1928/*
1929 * function: zfcp_fsf_open_port_handler
1930 *
1931 * purpose: is called for finished Open Port command
1932 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +02001933 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 */
1935static int
1936zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
1937{
1938 int retval = -EINVAL;
1939 struct zfcp_port *port;
1940 struct fsf_plogi *plogi;
1941 struct fsf_qtcb_header *header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Andreas Herrmann059c97d2005-09-13 21:47:52 +02001943 port = (struct zfcp_port *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 header = &fsf_req->qtcb->header;
1945
1946 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
1947 /* don't change port status in our bookkeeping */
1948 goto skip_fsfstatus;
1949 }
1950
1951 /* evaluate FSF status in QTCB */
1952 switch (header->fsf_status) {
1953
1954 case FSF_PORT_ALREADY_OPEN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 /*
1956 * This is a bug, however operation should continue normally
1957 * if it is simply ignored
1958 */
1959 break;
1960
1961 case FSF_ACCESS_DENIED:
Christof Schmitt553448f2008-06-10 18:20:58 +02001962 zfcp_fsf_access_denied_port(fsf_req, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 break;
1964
1965 case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
Christof Schmitt553448f2008-06-10 18:20:58 +02001966 dev_warn(&fsf_req->adapter->ccw_device->dev,
1967 "The adapter is out of resources. The remote port "
1968 "0x%016Lx could not be opened, disabling it.\n",
1969 port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02001970 zfcp_erp_port_failed(port, 31, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1972 break;
1973
1974 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 switch (header->fsf_status_qual.word[0]) {
1976 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 /* ERP strategy will escalate */
1978 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1979 break;
1980 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
1981 /* ERP strategy will escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1983 break;
1984 case FSF_SQ_NO_RETRY_POSSIBLE:
Christof Schmitt553448f2008-06-10 18:20:58 +02001985 dev_warn(&fsf_req->adapter->ccw_device->dev,
1986 "The remote port 0x%016Lx could not be "
1987 "opened. Disabling it.\n", port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02001988 zfcp_erp_port_failed(port, 32, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
1990 break;
1991 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 break;
1993 }
1994 break;
1995
1996 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 /* save port handle assigned by FSF */
1998 port->handle = header->port_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 /* mark port as open */
2000 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
2001 ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02002002 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
2003 ZFCP_STATUS_COMMON_ACCESS_BOXED,
2004 &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 retval = 0;
2006 /* check whether D_ID has changed during open */
2007 /*
2008 * FIXME: This check is not airtight, as the FCP channel does
2009 * not monitor closures of target port connections caused on
2010 * the remote side. Thus, they might miss out on invalidating
2011 * locally cached WWPNs (and other N_Port parameters) of gone
2012 * target ports. So, our heroic attempt to make things safe
2013 * could be undermined by 'open port' response data tagged with
2014 * obsolete WWPNs. Another reason to monitor potential
2015 * connection closures ourself at least (by interpreting
2016 * incoming ELS' and unsolicited status). It just crosses my
2017 * mind that one should be able to cross-check by means of
2018 * another GID_PN straight after a port has been opened.
2019 * Alternately, an ADISC/PDISC ELS should suffice, as well.
2020 */
2021 plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els;
2022 if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status))
2023 {
2024 if (fsf_req->qtcb->bottom.support.els1_length <
Ralph Wuerthner75bfc282006-05-22 18:24:33 +02002025 sizeof (struct fsf_plogi)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 /* skip sanity check and assume wwpn is ok */
2027 } else {
2028 if (plogi->serv_param.wwpn != port->wwpn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 atomic_clear_mask(
2030 ZFCP_STATUS_PORT_DID_DID,
2031 &port->status);
Ralph Wuerthner75bfc282006-05-22 18:24:33 +02002032 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 port->wwnn = plogi->serv_param.wwnn;
Christof Schmitt24073b42008-06-10 18:20:54 +02002034 zfcp_fc_plogi_evaluate(port, plogi);
Ralph Wuerthner75bfc282006-05-22 18:24:33 +02002035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
2037 }
2038 break;
2039
2040 case FSF_UNKNOWN_OP_SUBTYPE:
2041 /* should never occure, subtype not set in zfcp_fsf_open_port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2043 break;
2044
2045 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 break;
2047 }
2048
2049 skip_fsfstatus:
2050 atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
2051 return retval;
2052}
2053
2054/*
2055 * function: zfcp_fsf_close_port
2056 *
2057 * purpose: submit FSF command "close port"
2058 *
2059 * returns: address of initiated FSF request
2060 * NULL - request could not be initiated
2061 */
2062int
2063zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
2064{
2065 volatile struct qdio_buffer_element *sbale;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002066 struct zfcp_fsf_req *fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 unsigned long lock_flags;
2068 int retval = 0;
2069
2070 /* setup new FSF request */
2071 retval = zfcp_fsf_req_create(erp_action->adapter,
2072 FSF_QTCB_CLOSE_PORT,
2073 ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
2074 erp_action->adapter->pool.fsf_req_erp,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002075 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002076 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Swen Schillig00bab912008-06-10 18:20:57 +02002079 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
2081 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2082
2083 atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002084 fsf_req->data = (unsigned long) erp_action->port;
2085 fsf_req->erp_action = erp_action;
2086 fsf_req->qtcb->header.port_handle = erp_action->port->handle;
2087 fsf_req->erp_action = erp_action;
2088 erp_action->fsf_req = fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002090 zfcp_erp_start_timer(fsf_req);
2091 retval = zfcp_fsf_req_send(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 if (retval) {
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002093 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 erp_action->fsf_req = NULL;
2095 goto out;
2096 }
2097
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 out:
Swen Schillig00bab912008-06-10 18:20:57 +02002099 write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 return retval;
2101}
2102
2103/*
2104 * function: zfcp_fsf_close_port_handler
2105 *
2106 * purpose: is called for finished Close Port FSF command
2107 *
2108 * returns:
2109 */
2110static int
2111zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req)
2112{
2113 int retval = -EINVAL;
2114 struct zfcp_port *port;
2115
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002116 port = (struct zfcp_port *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
2118 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
2119 /* don't change port status in our bookkeeping */
2120 goto skip_fsfstatus;
2121 }
2122
2123 /* evaluate FSF status in QTCB */
2124 switch (fsf_req->qtcb->header.fsf_status) {
2125
2126 case FSF_PORT_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002127 zfcp_erp_adapter_reopen(port->adapter, 0, 107, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2129 break;
2130
2131 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 /* Note: FSF has actually closed the port in this case.
2133 * The status code is just daft. Fingers crossed for a change
2134 */
2135 retval = 0;
2136 break;
2137
2138 case FSF_GOOD:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002139 zfcp_erp_modify_port_status(port, 33, fsf_req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 ZFCP_STATUS_COMMON_OPEN,
2141 ZFCP_CLEAR);
2142 retval = 0;
2143 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 }
2145
2146 skip_fsfstatus:
2147 atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
2148 return retval;
2149}
2150
2151/*
2152 * function: zfcp_fsf_close_physical_port
2153 *
2154 * purpose: submit FSF command "close physical port"
2155 *
2156 * returns: address of initiated FSF request
2157 * NULL - request could not be initiated
2158 */
2159int
2160zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
2161{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 volatile struct qdio_buffer_element *sbale;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002163 struct zfcp_fsf_req *fsf_req;
2164 unsigned long lock_flags;
2165 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 /* setup new FSF request */
2168 retval = zfcp_fsf_req_create(erp_action->adapter,
2169 FSF_QTCB_CLOSE_PHYSICAL_PORT,
2170 ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
2171 erp_action->adapter->pool.fsf_req_erp,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002172 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002173 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
Swen Schillig00bab912008-06-10 18:20:57 +02002176 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
2178 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2179
2180 /* mark port as being closed */
2181 atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
2182 &erp_action->port->status);
2183 /* save a pointer to this port */
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002184 fsf_req->data = (unsigned long) erp_action->port;
2185 fsf_req->qtcb->header.port_handle = erp_action->port->handle;
2186 fsf_req->erp_action = erp_action;
2187 erp_action->fsf_req = fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002189 zfcp_erp_start_timer(fsf_req);
2190 retval = zfcp_fsf_req_send(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 if (retval) {
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002192 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 erp_action->fsf_req = NULL;
2194 goto out;
2195 }
2196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 out:
Swen Schillig00bab912008-06-10 18:20:57 +02002198 write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 return retval;
2200}
2201
2202/*
2203 * function: zfcp_fsf_close_physical_port_handler
2204 *
2205 * purpose: is called for finished Close Physical Port FSF command
2206 *
2207 * returns:
2208 */
2209static int
2210zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req)
2211{
2212 int retval = -EINVAL;
2213 struct zfcp_port *port;
2214 struct zfcp_unit *unit;
2215 struct fsf_qtcb_header *header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002217 port = (struct zfcp_port *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 header = &fsf_req->qtcb->header;
2219
2220 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
2221 /* don't change port status in our bookkeeping */
2222 goto skip_fsfstatus;
2223 }
2224
2225 /* evaluate FSF status in QTCB */
2226 switch (header->fsf_status) {
2227
2228 case FSF_PORT_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002229 zfcp_erp_adapter_reopen(port->adapter, 0, 108, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2231 break;
2232
2233 case FSF_ACCESS_DENIED:
Christof Schmitt553448f2008-06-10 18:20:58 +02002234 zfcp_fsf_access_denied_port(fsf_req, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 break;
2236
2237 case FSF_PORT_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002238 zfcp_erp_port_boxed(port, 50, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2240 ZFCP_STATUS_FSFREQ_RETRY;
Christof Schmitt5c815d12008-03-10 16:18:54 +01002241
2242 /* can't use generic zfcp_erp_modify_port_status because
2243 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
2244 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
2245 list_for_each_entry(unit, &port->unit_list_head, list)
2246 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
2247 &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 break;
2249
2250 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 switch (header->fsf_status_qual.word[0]) {
2252 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 /* This will now be escalated by ERP */
2254 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2255 break;
2256 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 /* ERP strategy will escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2259 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
2261 break;
2262
2263 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 /* can't use generic zfcp_erp_modify_port_status because
2265 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port
2266 */
2267 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
2268 list_for_each_entry(unit, &port->unit_list_head, list)
2269 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
2270 retval = 0;
2271 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
2273
2274 skip_fsfstatus:
2275 atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
2276 return retval;
2277}
2278
2279/*
2280 * function: zfcp_fsf_open_unit
2281 *
2282 * purpose:
2283 *
2284 * returns:
2285 *
2286 * assumptions: This routine does not check whether the associated
2287 * remote port has already been opened. This should be
2288 * done by calling routines. Otherwise some status
2289 * may be presented by FSF
2290 */
2291int
2292zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
2293{
2294 volatile struct qdio_buffer_element *sbale;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002295 struct zfcp_fsf_req *fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 unsigned long lock_flags;
2297 int retval = 0;
2298
2299 /* setup new FSF request */
2300 retval = zfcp_fsf_req_create(erp_action->adapter,
2301 FSF_QTCB_OPEN_LUN,
2302 ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
2303 erp_action->adapter->pool.fsf_req_erp,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002304 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002305 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Swen Schillig00bab912008-06-10 18:20:57 +02002308 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
2310 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2311
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002312 fsf_req->qtcb->header.port_handle = erp_action->port->handle;
2313 fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02002314 if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE))
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002315 fsf_req->qtcb->bottom.support.option =
Andreas Herrmann06506d02006-05-22 18:18:19 +02002316 FSF_OPEN_LUN_SUPPRESS_BOXING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002318 fsf_req->data = (unsigned long) erp_action->unit;
2319 fsf_req->erp_action = erp_action;
2320 erp_action->fsf_req = fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002322 zfcp_erp_start_timer(fsf_req);
2323 retval = zfcp_fsf_req_send(erp_action->fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 if (retval) {
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002325 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 erp_action->fsf_req = NULL;
2327 goto out;
2328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 out:
Swen Schillig00bab912008-06-10 18:20:57 +02002330 write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 return retval;
2332}
2333
2334/*
2335 * function: zfcp_fsf_open_unit_handler
2336 *
2337 * purpose: is called for finished Open LUN command
2338 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +02002339 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 */
2341static int
2342zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
2343{
2344 int retval = -EINVAL;
2345 struct zfcp_adapter *adapter;
2346 struct zfcp_unit *unit;
2347 struct fsf_qtcb_header *header;
2348 struct fsf_qtcb_bottom_support *bottom;
2349 struct fsf_queue_designator *queue_designator;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02002350 int exclusive, readwrite;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002352 unit = (struct zfcp_unit *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
2354 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
2355 /* don't change unit status in our bookkeeping */
2356 goto skip_fsfstatus;
2357 }
2358
2359 adapter = fsf_req->adapter;
2360 header = &fsf_req->qtcb->header;
2361 bottom = &fsf_req->qtcb->bottom.support;
2362 queue_designator = &header->fsf_status_qual.fsf_queue_designator;
2363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Heiko Carstensb64ddf92007-05-08 11:19:57 +02002365 ZFCP_STATUS_COMMON_ACCESS_BOXED |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 ZFCP_STATUS_UNIT_SHARED |
2367 ZFCP_STATUS_UNIT_READONLY,
2368 &unit->status);
2369
2370 /* evaluate FSF status in QTCB */
2371 switch (header->fsf_status) {
2372
2373 case FSF_PORT_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002374 zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2376 break;
2377
2378 case FSF_LUN_ALREADY_OPEN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2380 break;
2381
2382 case FSF_ACCESS_DENIED:
Christof Schmitt553448f2008-06-10 18:20:58 +02002383 zfcp_fsf_access_denied_unit(fsf_req, unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
Christof Schmitt553448f2008-06-10 18:20:58 +02002385 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 break;
2387
2388 case FSF_PORT_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002389 zfcp_erp_port_boxed(unit->port, 51, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2391 ZFCP_STATUS_FSFREQ_RETRY;
2392 break;
2393
2394 case FSF_LUN_SHARING_VIOLATION:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 if (header->fsf_status_qual.word[0] != 0) {
Christof Schmitt553448f2008-06-10 18:20:58 +02002396 dev_warn(&adapter->ccw_device->dev,
2397 "FCP-LUN 0x%Lx at the remote port "
2398 "with WWPN 0x%Lx "
2399 "connected to the adapter "
2400 "is already in use in LPAR%d, CSS%d.\n",
2401 unit->fcp_lun,
2402 unit->port->wwpn,
2403 queue_designator->hla,
2404 queue_designator->cssid);
2405 } else
2406 zfcp_act_eval_err(adapter,
2407 header->fsf_status_qual.word[2]);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002408 zfcp_erp_unit_access_denied(unit, 60, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status);
2410 atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status);
2411 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2412 break;
2413
2414 case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
Christof Schmitt553448f2008-06-10 18:20:58 +02002415 dev_warn(&fsf_req->adapter->ccw_device->dev,
2416 "The adapter ran out of resources. There is no "
2417 "handle available for unit 0x%016Lx on port 0x%016Lx.",
2418 unit->fcp_lun, unit->port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002419 zfcp_erp_unit_failed(unit, 34, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2421 break;
2422
2423 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 switch (header->fsf_status_qual.word[0]) {
2425 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 /* Re-establish link to port */
Andreas Herrmann65a8d4e2005-06-13 13:16:27 +02002427 zfcp_test_link(unit->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2429 break;
2430 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 /* ERP strategy will escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
2435 break;
2436
2437 case FSF_INVALID_COMMAND_OPTION:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2439 retval = -EINVAL;
2440 break;
2441
2442 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 /* save LUN handle assigned by FSF */
2444 unit->handle = header->lun_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 /* mark unit as open */
2446 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02002447
2448 if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
2449 (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
2450 (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
2451 exclusive = (bottom->lun_access_info &
2452 FSF_UNIT_ACCESS_EXCLUSIVE);
2453 readwrite = (bottom->lun_access_info &
2454 FSF_UNIT_ACCESS_OUTBOUND_TRANSFER);
2455
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 if (!exclusive)
2457 atomic_set_mask(ZFCP_STATUS_UNIT_SHARED,
2458 &unit->status);
2459
2460 if (!readwrite) {
2461 atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
2462 &unit->status);
Christof Schmitt553448f2008-06-10 18:20:58 +02002463 dev_info(&fsf_req->adapter->ccw_device->dev,
2464 "Read-only access for unit 0x%016Lx "
2465 "on port 0x%016Lx.\n",
2466 unit->fcp_lun, unit->port->wwpn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 }
2468
2469 if (exclusive && !readwrite) {
Christof Schmitt553448f2008-06-10 18:20:58 +02002470 dev_err(&fsf_req->adapter->ccw_device->dev,
2471 "Exclusive access of read-only unit "
2472 "0x%016Lx on port 0x%016Lx not "
2473 "supported, disabling unit.\n",
2474 unit->fcp_lun, unit->port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002475 zfcp_erp_unit_failed(unit, 35, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Martin Peschke1f6f7122008-04-18 12:51:55 +02002477 zfcp_erp_unit_shutdown(unit, 0, 80, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 } else if (!exclusive && readwrite) {
Christof Schmitt553448f2008-06-10 18:20:58 +02002479 dev_err(&fsf_req->adapter->ccw_device->dev,
2480 "Shared access of read-write unit "
2481 "0x%016Lx on port 0x%016Lx not "
2482 "supported, disabling unit.\n",
2483 unit->fcp_lun, unit->port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002484 zfcp_erp_unit_failed(unit, 36, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Martin Peschke1f6f7122008-04-18 12:51:55 +02002486 zfcp_erp_unit_shutdown(unit, 0, 81, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 }
2488 }
2489
2490 retval = 0;
2491 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 }
2493
2494 skip_fsfstatus:
2495 atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
2496 return retval;
2497}
2498
2499/*
2500 * function: zfcp_fsf_close_unit
2501 *
2502 * purpose:
2503 *
2504 * returns: address of fsf_req - request successfully initiated
Swen Schillig41fa2ad2007-09-07 09:15:31 +02002505 * NULL -
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 *
2507 * assumptions: This routine does not check whether the associated
2508 * remote port/lun has already been opened. This should be
2509 * done by calling routines. Otherwise some status
2510 * may be presented by FSF
2511 */
2512int
2513zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
2514{
2515 volatile struct qdio_buffer_element *sbale;
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002516 struct zfcp_fsf_req *fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 unsigned long lock_flags;
2518 int retval = 0;
2519
2520 /* setup new FSF request */
2521 retval = zfcp_fsf_req_create(erp_action->adapter,
2522 FSF_QTCB_CLOSE_LUN,
2523 ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
2524 erp_action->adapter->pool.fsf_req_erp,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002525 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002526 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
Swen Schillig00bab912008-06-10 18:20:57 +02002529 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
2531 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2532
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002533 fsf_req->qtcb->header.port_handle = erp_action->port->handle;
2534 fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002536 fsf_req->data = (unsigned long) erp_action->unit;
2537 fsf_req->erp_action = erp_action;
2538 erp_action->fsf_req = fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002540 zfcp_erp_start_timer(fsf_req);
2541 retval = zfcp_fsf_req_send(erp_action->fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 if (retval) {
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002543 zfcp_fsf_req_free(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 erp_action->fsf_req = NULL;
2545 goto out;
2546 }
2547
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 out:
Swen Schillig00bab912008-06-10 18:20:57 +02002549 write_unlock_irqrestore(&erp_action->adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 return retval;
2551}
2552
2553/*
2554 * function: zfcp_fsf_close_unit_handler
2555 *
2556 * purpose: is called for finished Close LUN FSF command
2557 *
2558 * returns:
2559 */
2560static int
2561zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req)
2562{
2563 int retval = -EINVAL;
2564 struct zfcp_unit *unit;
2565
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002566 unit = (struct zfcp_unit *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
2568 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
2569 /* don't change unit status in our bookkeeping */
2570 goto skip_fsfstatus;
2571 }
2572
2573 /* evaluate FSF status in QTCB */
2574 switch (fsf_req->qtcb->header.fsf_status) {
2575
2576 case FSF_PORT_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002577 zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2579 break;
2580
2581 case FSF_LUN_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002582 zfcp_erp_port_reopen(unit->port, 0, 111, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2584 break;
2585
2586 case FSF_PORT_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002587 zfcp_erp_port_boxed(unit->port, 52, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2589 ZFCP_STATUS_FSFREQ_RETRY;
2590 break;
2591
2592 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) {
2594 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 /* re-establish link to port */
Andreas Herrmann65a8d4e2005-06-13 13:16:27 +02002596 zfcp_test_link(unit->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2598 break;
2599 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 /* ERP strategy will escalate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2602 break;
2603 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 break;
2605 }
2606 break;
2607
2608 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 /* mark unit as closed */
2610 atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
2611 retval = 0;
2612 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 }
2614
2615 skip_fsfstatus:
2616 atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
2617 return retval;
2618}
2619
2620/**
2621 * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
2622 * @adapter: adapter where scsi command is issued
2623 * @unit: unit where command is sent to
2624 * @scsi_cmnd: scsi command to be sent
2625 * @timer: timer to be started when request is initiated
2626 * @req_flags: flags for fsf_request
2627 */
2628int
2629zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
2630 struct zfcp_unit *unit,
2631 struct scsi_cmnd * scsi_cmnd,
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002632 int use_timer, int req_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633{
2634 struct zfcp_fsf_req *fsf_req = NULL;
2635 struct fcp_cmnd_iu *fcp_cmnd_iu;
2636 unsigned int sbtype;
2637 unsigned long lock_flags;
2638 int real_bytes = 0;
2639 int retval = 0;
2640 int mask;
2641
2642 /* setup new FSF request */
2643 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2644 adapter->pool.fsf_req_scsi,
2645 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002646 if (unlikely(retval < 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 goto failed_req_create;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
Christof Schmittba172422007-12-20 12:30:26 +01002649 if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
2650 &unit->status))) {
2651 retval = -EBUSY;
2652 goto unit_blocked;
2653 }
2654
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002655 zfcp_unit_get(unit);
2656 fsf_req->unit = unit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002658 /* associate FSF request with SCSI request (for look up on abort) */
Andreas Herrmann4eff4a32006-09-18 22:29:20 +02002659 scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id;
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002660
2661 /* associate SCSI command with FSF request */
2662 fsf_req->data = (unsigned long) scsi_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664 /* set handles of unit and its parent port in QTCB */
2665 fsf_req->qtcb->header.lun_handle = unit->handle;
2666 fsf_req->qtcb->header.port_handle = unit->port->handle;
2667
2668 /* FSF does not define the structure of the FCP_CMND IU */
2669 fcp_cmnd_iu = (struct fcp_cmnd_iu *)
2670 &(fsf_req->qtcb->bottom.io.fcp_cmnd);
2671
2672 /*
2673 * set depending on data direction:
2674 * data direction bits in SBALE (SB Type)
2675 * data direction bits in QTCB
2676 * data direction bits in FCP_CMND IU
2677 */
2678 switch (scsi_cmnd->sc_data_direction) {
2679 case DMA_NONE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2681 /*
2682 * FIXME(qdio):
2683 * what is the correct type for commands
2684 * without 'real' data buffers?
2685 */
2686 sbtype = SBAL_FLAGS0_TYPE_READ;
2687 break;
2688 case DMA_FROM_DEVICE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2690 sbtype = SBAL_FLAGS0_TYPE_READ;
2691 fcp_cmnd_iu->rddata = 1;
2692 break;
2693 case DMA_TO_DEVICE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2695 sbtype = SBAL_FLAGS0_TYPE_WRITE;
2696 fcp_cmnd_iu->wddata = 1;
2697 break;
2698 case DMA_BIDIRECTIONAL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 default:
2700 /*
2701 * dummy, catch this condition earlier
2702 * in zfcp_scsi_queuecommand
2703 */
2704 goto failed_scsi_cmnd;
2705 }
2706
2707 /* set FC service class in QTCB (3 per default) */
Andreas Herrmann06506d02006-05-22 18:18:19 +02002708 fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
2710 /* set FCP_LUN in FCP_CMND IU in QTCB */
2711 fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2712
2713 mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED;
2714
2715 /* set task attributes in FCP_CMND IU in QTCB */
2716 if (likely((scsi_cmnd->device->simple_tags) ||
2717 (atomic_test_mask(mask, &unit->status))))
2718 fcp_cmnd_iu->task_attribute = SIMPLE_Q;
2719 else
2720 fcp_cmnd_iu->task_attribute = UNTAGGED;
2721
2722 /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
Christof Schmitt553448f2008-06-10 18:20:58 +02002723 if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 fcp_cmnd_iu->add_fcp_cdb_length
2725 = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 /*
2727 * copy SCSI CDB (including additional length, if any) to
2728 * FCP_CDB in FCP_CMND IU in QTCB
2729 */
2730 memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
2731
2732 /* FCP CMND IU length in QTCB */
2733 fsf_req->qtcb->bottom.io.fcp_cmnd_length =
2734 sizeof (struct fcp_cmnd_iu) +
2735 fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t);
2736
2737 /* generate SBALEs from data buffer */
Swen Schillig00bab912008-06-10 18:20:57 +02002738 real_bytes = zfcp_qdio_sbals_from_sg(fsf_req, sbtype,
2739 scsi_sglist(scsi_cmnd),
2740 ZFCP_MAX_SBALS_PER_REQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 if (unlikely(real_bytes < 0)) {
Christof Schmitt553448f2008-06-10 18:20:58 +02002742 if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ)
Christof Schmitt2282f652007-08-28 09:30:22 +02002743 retval = -EIO;
Christof Schmitt553448f2008-06-10 18:20:58 +02002744 else {
2745 dev_err(&adapter->ccw_device->dev,
2746 "SCSI request too large. "
2747 "Shutting down unit 0x%016Lx on port "
2748 "0x%016Lx.\n", unit->fcp_lun,
2749 unit->port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002750 zfcp_erp_unit_shutdown(unit, 0, 131, fsf_req);
Christof Schmitt2282f652007-08-28 09:30:22 +02002751 retval = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 }
2753 goto no_fit;
2754 }
2755
2756 /* set length of FCP data length in FCP_CMND IU in QTCB */
2757 zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
2758
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002759 if (use_timer)
2760 zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
2761
2762 retval = zfcp_fsf_req_send(fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002763 if (unlikely(retval < 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 goto send_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 goto success;
2767
2768 send_failed:
2769 no_fit:
2770 failed_scsi_cmnd:
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002771 zfcp_unit_put(unit);
Christof Schmitt57b76582008-04-18 12:51:57 +02002772 unit_blocked:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 zfcp_fsf_req_free(fsf_req);
2774 fsf_req = NULL;
2775 scsi_cmnd->host_scribble = NULL;
2776 success:
2777 failed_req_create:
Swen Schillig00bab912008-06-10 18:20:57 +02002778 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 return retval;
2780}
2781
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782struct zfcp_fsf_req *
2783zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
2784 struct zfcp_unit *unit,
2785 u8 tm_flags, int req_flags)
2786{
2787 struct zfcp_fsf_req *fsf_req = NULL;
2788 int retval = 0;
2789 struct fcp_cmnd_iu *fcp_cmnd_iu;
2790 unsigned long lock_flags;
2791 volatile struct qdio_buffer_element *sbale;
2792
2793 /* setup new FSF request */
2794 retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
2795 adapter->pool.fsf_req_scsi,
2796 &lock_flags, &fsf_req);
Christof Schmitt553448f2008-06-10 18:20:58 +02002797 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
Christof Schmittfdf23452007-12-20 12:30:27 +01002800 if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
2801 &unit->status)))
2802 goto unit_blocked;
2803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 /*
2805 * Used to decide on proper handler in the return path,
2806 * could be either zfcp_fsf_send_fcp_command_task_handler or
2807 * zfcp_fsf_send_fcp_command_task_management_handler */
2808
2809 fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
2810
2811 /*
2812 * hold a pointer to the unit being target of this
2813 * task management request
2814 */
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002815 fsf_req->data = (unsigned long) unit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
2817 /* set FSF related fields in QTCB */
2818 fsf_req->qtcb->header.lun_handle = unit->handle;
2819 fsf_req->qtcb->header.port_handle = unit->port->handle;
2820 fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
Andreas Herrmann06506d02006-05-22 18:18:19 +02002821 fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 fsf_req->qtcb->bottom.io.fcp_cmnd_length =
2823 sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t);
2824
Swen Schillig00bab912008-06-10 18:20:57 +02002825 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
2827 sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
2828
2829 /* set FCP related fields in FCP_CMND IU in QTCB */
2830 fcp_cmnd_iu = (struct fcp_cmnd_iu *)
2831 &(fsf_req->qtcb->bottom.io.fcp_cmnd);
2832 fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
2833 fcp_cmnd_iu->task_management_flags = tm_flags;
2834
Andreas Herrmann2abbe862006-09-18 22:29:56 +02002835 zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
2836 retval = zfcp_fsf_req_send(fsf_req);
Christof Schmittfdf23452007-12-20 12:30:27 +01002837 if (!retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
Christof Schmittfdf23452007-12-20 12:30:27 +01002840 unit_blocked:
2841 zfcp_fsf_req_free(fsf_req);
2842 fsf_req = NULL;
2843
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 out:
Swen Schillig00bab912008-06-10 18:20:57 +02002845 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 return fsf_req;
2847}
2848
Christof Schmittc9615852008-05-06 11:00:05 +02002849static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
2850{
2851 lat_rec->sum += lat;
2852 if (lat_rec->min > lat)
2853 lat_rec->min = lat;
2854 if (lat_rec->max < lat)
2855 lat_rec->max = lat;
2856}
2857
2858static void zfcp_fsf_req_latency(struct zfcp_fsf_req *fsf_req)
2859{
2860 struct fsf_qual_latency_info *lat_inf;
2861 struct latency_cont *lat;
2862 struct zfcp_unit *unit;
2863 unsigned long flags;
2864
2865 lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
2866 unit = fsf_req->unit;
2867
2868 switch (fsf_req->qtcb->bottom.io.data_direction) {
2869 case FSF_DATADIR_READ:
2870 lat = &unit->latencies.read;
2871 break;
2872 case FSF_DATADIR_WRITE:
2873 lat = &unit->latencies.write;
2874 break;
2875 case FSF_DATADIR_CMND:
2876 lat = &unit->latencies.cmd;
2877 break;
2878 default:
2879 return;
2880 }
2881
2882 spin_lock_irqsave(&unit->latencies.lock, flags);
2883 zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
2884 zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
2885 lat->counter++;
2886 spin_unlock_irqrestore(&unit->latencies.lock, flags);
2887}
2888
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889/*
2890 * function: zfcp_fsf_send_fcp_command_handler
2891 *
2892 * purpose: is called for finished Send FCP Command
2893 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +02002894 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 */
2896static int
2897zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
2898{
2899 int retval = -EINVAL;
2900 struct zfcp_unit *unit;
2901 struct fsf_qtcb_header *header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
2903 header = &fsf_req->qtcb->header;
2904
2905 if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT))
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002906 unit = (struct zfcp_unit *) fsf_req->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 else
Andreas Herrmann059c97d2005-09-13 21:47:52 +02002908 unit = fsf_req->unit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
2910 if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
2911 /* go directly to calls of special handlers */
2912 goto skip_fsfstatus;
2913 }
2914
2915 /* evaluate FSF status in QTCB */
2916 switch (header->fsf_status) {
2917
2918 case FSF_PORT_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002919 zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2921 break;
2922
2923 case FSF_LUN_HANDLE_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002924 zfcp_erp_port_reopen(unit->port, 0, 113, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2926 break;
2927
2928 case FSF_HANDLE_MISMATCH:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002929 zfcp_erp_adapter_reopen(unit->port->adapter, 0, 114, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2931 break;
2932
2933 case FSF_SERVICE_CLASS_NOT_SUPPORTED:
Christof Schmitt553448f2008-06-10 18:20:58 +02002934 zfcp_fsf_class_not_supp(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 break;
2936
2937 case FSF_FCPLUN_NOT_VALID:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002938 zfcp_erp_port_reopen(unit->port, 0, 115, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2940 break;
2941
2942 case FSF_ACCESS_DENIED:
Christof Schmitt553448f2008-06-10 18:20:58 +02002943 zfcp_fsf_access_denied_unit(fsf_req, unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 break;
2945
2946 case FSF_DIRECTION_INDICATOR_NOT_VALID:
Christof Schmitt553448f2008-06-10 18:20:58 +02002947 dev_err(&fsf_req->adapter->ccw_device->dev,
2948 "Invalid data direction (%d) given for unit 0x%016Lx "
2949 "on port 0x%016Lx, shutting down adapter.\n",
2950 fsf_req->qtcb->bottom.io.data_direction,
2951 unit->fcp_lun, unit->port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002952 zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2954 break;
2955
2956 case FSF_CMND_LENGTH_NOT_VALID:
Christof Schmitt553448f2008-06-10 18:20:58 +02002957 dev_err(&fsf_req->adapter->ccw_device->dev,
2958 "An invalid control-data-block length field (%d) "
2959 "was found in a command for unit 0x%016Lx on port "
2960 "0x%016Lx. Shutting down adapter.\n",
2961 fsf_req->qtcb->bottom.io.fcp_cmnd_length,
2962 unit->fcp_lun, unit->port->wwpn);
Martin Peschke1f6f7122008-04-18 12:51:55 +02002963 zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
2965 break;
2966
2967 case FSF_PORT_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002968 zfcp_erp_port_boxed(unit->port, 53, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |
2970 ZFCP_STATUS_FSFREQ_RETRY;
2971 break;
2972
2973 case FSF_LUN_BOXED:
Martin Peschke1f6f7122008-04-18 12:51:55 +02002974 zfcp_erp_unit_boxed(unit, 54, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR
2976 | ZFCP_STATUS_FSFREQ_RETRY;
2977 break;
2978
2979 case FSF_ADAPTER_STATUS_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 switch (header->fsf_status_qual.word[0]) {
2981 case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 /* re-establish link to port */
Andreas Herrmann65a8d4e2005-06-13 13:16:27 +02002983 zfcp_test_link(unit->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 break;
2985 case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 /* FIXME(hw) need proper specs for proper action */
2987 /* let scsi stack deal with retries and escalation */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 }
Andreas Herrmann516a4202005-06-13 13:17:44 +02002990 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 break;
2992
2993 case FSF_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 break;
2995
2996 case FSF_FCP_RSP_AVAILABLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 }
2999
3000 skip_fsfstatus:
3001 if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) {
3002 retval =
3003 zfcp_fsf_send_fcp_command_task_management_handler(fsf_req);
3004 } else {
3005 retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req);
Andreas Herrmann059c97d2005-09-13 21:47:52 +02003006 fsf_req->unit = NULL;
3007 zfcp_unit_put(unit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 }
3009 return retval;
3010}
3011
3012/*
3013 * function: zfcp_fsf_send_fcp_command_task_handler
3014 *
3015 * purpose: evaluates FCP_RSP IU
3016 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +02003017 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 */
3019static int
3020zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
3021{
3022 int retval = 0;
3023 struct scsi_cmnd *scpnt;
3024 struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
3025 &(fsf_req->qtcb->bottom.io.fcp_rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 u32 sns_len;
3027 char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
3028 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
3030 read_lock_irqsave(&fsf_req->adapter->abort_lock, flags);
Andreas Herrmann059c97d2005-09-13 21:47:52 +02003031 scpnt = (struct scsi_cmnd *) fsf_req->data;
Christof Schmitt553448f2008-06-10 18:20:58 +02003032 if (unlikely(!scpnt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 goto out;
Christof Schmitt553448f2008-06-10 18:20:58 +02003034
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
3036 /* FIXME: (design) mid-layer should handle DID_ABORT like
3037 * DID_SOFT_ERROR by retrying the request for devices
3038 * that allow retries.
3039 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 set_host_byte(&scpnt->result, DID_SOFT_ERROR);
3041 set_driver_byte(&scpnt->result, SUGGEST_RETRY);
3042 goto skip_fsfstatus;
3043 }
3044
3045 if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 set_host_byte(&scpnt->result, DID_ERROR);
3047 goto skip_fsfstatus;
3048 }
3049
3050 /* set message byte of result in SCSI command */
3051 scpnt->result |= COMMAND_COMPLETE << 8;
3052
3053 /*
3054 * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte
3055 * of result in SCSI command
3056 */
3057 scpnt->result |= fcp_rsp_iu->scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
Christof Schmittc9615852008-05-06 11:00:05 +02003059 if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
3060 zfcp_fsf_req_latency(fsf_req);
3061
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 /* check FCP_RSP_INFO */
3063 if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 switch (fcp_rsp_info[3]) {
3065 case RSP_CODE_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 /* ok, continue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 set_host_byte(&scpnt->result, DID_OK);
3068 break;
3069 case RSP_CODE_LENGTH_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 /* hardware bug */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 set_host_byte(&scpnt->result, DID_ERROR);
3072 goto skip_fsfstatus;
3073 case RSP_CODE_FIELD_INVALID:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 /* driver or hardware bug */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 set_host_byte(&scpnt->result, DID_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 goto skip_fsfstatus;
3077 case RSP_CODE_RO_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 /* hardware bug */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 set_host_byte(&scpnt->result, DID_ERROR);
3080 goto skip_fsfstatus;
3081 default:
Christof Schmitt553448f2008-06-10 18:20:58 +02003082 /* invalid FCP response code */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 set_host_byte(&scpnt->result, DID_ERROR);
6f71d9b2005-04-10 23:04:28 -05003084 goto skip_fsfstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 }
3086 }
3087
3088 /* check for sense data */
3089 if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) {
3090 sns_len = FSF_FCP_RSP_SIZE -
3091 sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
FUJITA Tomonori9d058ec2008-01-27 12:41:50 +09003095 memcpy(scpnt->sense_buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 }
3098
3099 /* check for underrun */
3100 if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) {
FUJITA Tomonori7936a892007-07-29 16:46:28 +09003101 scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
3102 if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
3103 scpnt->underflow)
6f71d9b2005-04-10 23:04:28 -05003104 set_host_byte(&scpnt->result, DID_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 }
3106
3107 skip_fsfstatus:
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003108 if (scpnt->result != 0)
Maxim Shchetynined829ad2006-02-11 01:42:58 +01003109 zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003110 else if (scpnt->retries > 0)
Maxim Shchetynined829ad2006-02-11 01:42:58 +01003111 zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req);
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003112 else
Maxim Shchetynined829ad2006-02-11 01:42:58 +01003113 zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115 /* cleanup pointer (need this especially for abort) */
3116 scpnt->host_scribble = NULL;
3117
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 /* always call back */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 (scpnt->scsi_done) (scpnt);
3120
3121 /*
3122 * We must hold this lock until scsi_done has been called.
3123 * Otherwise we may call scsi_done after abort regarding this
3124 * command has completed.
3125 * Note: scsi_done must not block!
3126 */
3127 out:
3128 read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags);
3129 return retval;
3130}
3131
3132/*
3133 * function: zfcp_fsf_send_fcp_command_task_management_handler
3134 *
3135 * purpose: evaluates FCP_RSP IU
3136 *
Swen Schillig41fa2ad2007-09-07 09:15:31 +02003137 * returns:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 */
3139static int
3140zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
3141{
3142 int retval = 0;
3143 struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *)
3144 &(fsf_req->qtcb->bottom.io.fcp_rsp);
3145 char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
3148 fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
3149 goto skip_fsfstatus;
3150 }
3151
3152 /* check FCP_RSP_INFO */
3153 switch (fcp_rsp_info[3]) {
3154 case RSP_CODE_GOOD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 /* ok, continue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 break;
3157 case RSP_CODE_TASKMAN_UNSUPP:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP;
3159 break;
3160 case RSP_CODE_TASKMAN_FAILED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
3162 break;
3163 default:
Christof Schmitt553448f2008-06-10 18:20:58 +02003164 /* invalid FCP response code */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
3166 }
3167
3168 skip_fsfstatus:
3169 return retval;
3170}
3171
3172
3173/*
3174 * function: zfcp_fsf_control_file
3175 *
3176 * purpose: Initiator of the control file upload/download FSF requests
3177 *
3178 * returns: 0 - FSF request is successfuly created and queued
3179 * -EOPNOTSUPP - The FCP adapter does not have Control File support
3180 * -EINVAL - Invalid direction specified
3181 * -ENOMEM - Insufficient memory
3182 * -EPERM - Cannot create FSF request or place it in QDIO queue
3183 */
Christof Schmitt45633fd2008-06-10 18:20:55 +02003184struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
3185 struct zfcp_fsf_cfdc *fsf_cfdc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186{
3187 struct zfcp_fsf_req *fsf_req;
3188 struct fsf_qtcb_bottom_support *bottom;
3189 volatile struct qdio_buffer_element *sbale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 unsigned long lock_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 int direction;
Christof Schmitt45633fd2008-06-10 18:20:55 +02003192 int retval;
3193 int bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Christof Schmitt45633fd2008-06-10 18:20:55 +02003195 if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
3196 return ERR_PTR(-EOPNOTSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Christof Schmitt45633fd2008-06-10 18:20:55 +02003198 switch (fsf_cfdc->command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
3200 direction = SBAL_FLAGS0_TYPE_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 case FSF_QTCB_UPLOAD_CONTROL_FILE:
3203 direction = SBAL_FLAGS0_TYPE_READ;
3204 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 default:
Christof Schmitt45633fd2008-06-10 18:20:55 +02003206 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 }
3208
Christof Schmitt45633fd2008-06-10 18:20:55 +02003209 retval = zfcp_fsf_req_create(adapter, fsf_cfdc->command,
3210 ZFCP_WAIT_FOR_SBAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 NULL, &lock_flags, &fsf_req);
3212 if (retval < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 retval = -EPERM;
3214 goto unlock_queue_lock;
3215 }
3216
Swen Schillig00bab912008-06-10 18:20:57 +02003217 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 sbale[0].flags |= direction;
3219
3220 bottom = &fsf_req->qtcb->bottom.support;
3221 bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
Christof Schmitt45633fd2008-06-10 18:20:55 +02003222 bottom->option = fsf_cfdc->option;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223
Christof Schmitt45633fd2008-06-10 18:20:55 +02003224 bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction,
Swen Schillig00bab912008-06-10 18:20:57 +02003225 fsf_cfdc->sg,
Christof Schmitt45633fd2008-06-10 18:20:55 +02003226 ZFCP_MAX_SBALS_PER_REQ);
3227 if (bytes != ZFCP_CFDC_MAX_SIZE) {
3228 retval = -ENOMEM;
3229 goto free_fsf_req;
3230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
Andreas Herrmann2abbe862006-09-18 22:29:56 +02003232 zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
3233 retval = zfcp_fsf_req_send(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 if (retval < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 retval = -EPERM;
3236 goto free_fsf_req;
3237 }
Swen Schillig00bab912008-06-10 18:20:57 +02003238 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 wait_event(fsf_req->completion_wq,
3241 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
3242
Christof Schmitt45633fd2008-06-10 18:20:55 +02003243 return fsf_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
3245 free_fsf_req:
3246 zfcp_fsf_req_free(fsf_req);
3247 unlock_queue_lock:
Swen Schillig00bab912008-06-10 18:20:57 +02003248 write_unlock_irqrestore(&adapter->req_q.lock, lock_flags);
Christof Schmitt45633fd2008-06-10 18:20:55 +02003249 return ERR_PTR(retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250}
3251
Christof Schmitt45633fd2008-06-10 18:20:55 +02003252static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253{
Christof Schmitt45633fd2008-06-10 18:20:55 +02003254 if (fsf_req->qtcb->header.fsf_status != FSF_GOOD)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256}
3257
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258static inline int
3259zfcp_fsf_req_sbal_check(unsigned long *flags,
3260 struct zfcp_qdio_queue *queue, int needed)
3261{
Swen Schillig00bab912008-06-10 18:20:57 +02003262 write_lock_irqsave(&queue->lock, *flags);
3263 if (likely(atomic_read(&queue->count) >= needed))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 return 1;
Swen Schillig00bab912008-06-10 18:20:57 +02003265 write_unlock_irqrestore(&queue->lock, *flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 return 0;
3267}
3268
3269/*
3270 * set qtcb pointer in fsf_req and initialize QTCB
3271 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +01003272static void
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003273zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274{
3275 if (likely(fsf_req->qtcb != NULL)) {
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003276 fsf_req->qtcb->prefix.req_seq_no =
3277 fsf_req->adapter->fsf_req_seq_no;
3278 fsf_req->qtcb->prefix.req_id = fsf_req->req_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003280 fsf_req->qtcb->prefix.qtcb_type =
3281 fsf_qtcb_type[fsf_req->fsf_command];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003283 fsf_req->qtcb->header.req_handle = fsf_req->req_id;
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003284 fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 }
3286}
3287
3288/**
3289 * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
3290 * @adapter: adapter for which request queue is examined
3291 * @req_flags: flags indicating whether to wait for needed SBAL or not
3292 * @lock_flags: lock_flags if queue_lock is taken
3293 * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS
Swen Schillig00bab912008-06-10 18:20:57 +02003294 * Locks: lock adapter->req_q->lock on success
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 */
3296static int
3297zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
3298 unsigned long *lock_flags)
3299{
3300 long ret;
Swen Schillig00bab912008-06-10 18:20:57 +02003301 struct zfcp_qdio_queue *req_q = &adapter->req_q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
3303 if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
3304 ret = wait_event_interruptible_timeout(adapter->request_wq,
Swen Schillig00bab912008-06-10 18:20:57 +02003305 zfcp_fsf_req_sbal_check(lock_flags, req_q, 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 ZFCP_SBAL_TIMEOUT);
3307 if (ret < 0)
3308 return ret;
3309 if (!ret)
3310 return -EIO;
Swen Schillig00bab912008-06-10 18:20:57 +02003311 } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_q, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 return -EIO;
3313
3314 return 0;
3315}
3316
3317/*
3318 * function: zfcp_fsf_req_create
3319 *
3320 * purpose: create an FSF request at the specified adapter and
3321 * setup common fields
3322 *
3323 * returns: -ENOMEM if there was insufficient memory for a request
3324 * -EIO if no qdio buffers could be allocate to the request
3325 * -EINVAL/-EPERM on bug conditions in req_dequeue
3326 * 0 in success
3327 *
3328 * note: The created request is returned by reference.
3329 *
3330 * locks: lock of concerned request queue must not be held,
3331 * but is held on completion (write, irqsave)
3332 */
3333int
3334zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
3335 mempool_t *pool, unsigned long *lock_flags,
3336 struct zfcp_fsf_req **fsf_req_p)
3337{
3338 volatile struct qdio_buffer_element *sbale;
3339 struct zfcp_fsf_req *fsf_req = NULL;
3340 int ret = 0;
Swen Schillig00bab912008-06-10 18:20:57 +02003341 struct zfcp_qdio_queue *req_q = &adapter->req_q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342
3343 /* allocate new FSF request */
3344 fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
Christof Schmitt553448f2008-06-10 18:20:58 +02003345 if (unlikely(!fsf_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 ret = -ENOMEM;
3347 goto failed_fsf_req;
3348 }
3349
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003350 fsf_req->adapter = adapter;
3351 fsf_req->fsf_command = fsf_cmd;
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003352 INIT_LIST_HEAD(&fsf_req->list);
Andreas Herrmann2abbe862006-09-18 22:29:56 +02003353 init_timer(&fsf_req->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
Swen Schillig41fa2ad2007-09-07 09:15:31 +02003355 /* initialize waitqueue which may be used to wait on
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 this request completion */
3357 init_waitqueue_head(&fsf_req->completion_wq);
3358
3359 ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
Christof Schmitt801e0ce2007-05-08 11:15:48 +02003360 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 goto failed_sbals;
Christof Schmitt801e0ce2007-05-08 11:15:48 +02003362
3363 /* this is serialized (we are holding req_queue-lock of adapter) */
3364 if (adapter->req_no == 0)
3365 adapter->req_no++;
3366 fsf_req->req_id = adapter->req_no++;
3367
3368 zfcp_fsf_req_qtcb_init(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
3370 /*
3371 * We hold queue_lock here. Check if QDIOUP is set and let request fail
3372 * if it is not set (see also *_open_qdio and *_close_qdio).
3373 */
3374
3375 if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
Swen Schillig00bab912008-06-10 18:20:57 +02003376 write_unlock_irqrestore(&req_q->lock, *lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 ret = -EIO;
3378 goto failed_sbals;
3379 }
3380
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003381 if (fsf_req->qtcb) {
3382 fsf_req->seq_no = adapter->fsf_req_seq_no;
3383 fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no;
3384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 fsf_req->sbal_number = 1;
Swen Schillig00bab912008-06-10 18:20:57 +02003386 fsf_req->sbal_first = req_q->first;
3387 fsf_req->sbal_last = req_q->first;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 fsf_req->sbale_curr = 1;
3389
3390 if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) {
3391 fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
3392 }
3393
Swen Schillig00bab912008-06-10 18:20:57 +02003394 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
3396 /* setup common SBALE fields */
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003397 sbale[0].addr = (void *) fsf_req->req_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 sbale[0].flags |= SBAL_FLAGS0_COMMAND;
3399 if (likely(fsf_req->qtcb != NULL)) {
3400 sbale[1].addr = (void *) fsf_req->qtcb;
3401 sbale[1].length = sizeof(struct fsf_qtcb);
3402 }
3403
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 goto success;
3405
3406 failed_sbals:
3407/* dequeue new FSF request previously enqueued */
3408 zfcp_fsf_req_free(fsf_req);
3409 fsf_req = NULL;
3410
3411 failed_fsf_req:
Swen Schillig00bab912008-06-10 18:20:57 +02003412 write_lock_irqsave(&req_q->lock, *lock_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 success:
3414 *fsf_req_p = fsf_req;
3415 return ret;
3416}
3417
3418/*
3419 * function: zfcp_fsf_req_send
3420 *
3421 * purpose: start transfer of FSF request via QDIO
3422 *
3423 * returns: 0 - request transfer succesfully started
3424 * !0 - start of request transfer failed
3425 */
Andreas Herrmann2abbe862006-09-18 22:29:56 +02003426static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427{
3428 struct zfcp_adapter *adapter;
Swen Schillig00bab912008-06-10 18:20:57 +02003429 struct zfcp_qdio_queue *req_q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 volatile struct qdio_buffer_element *sbale;
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003431 int inc_seq_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 int retval = 0;
3433
3434 adapter = fsf_req->adapter;
Swen Schillig00bab912008-06-10 18:20:57 +02003435 req_q = &adapter->req_q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
Swen Schillig00bab912008-06-10 18:20:57 +02003437 sbale = zfcp_qdio_sbale_req(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003439 /* put allocated FSF request into hash table */
3440 spin_lock(&adapter->req_list_lock);
3441 zfcp_reqlist_add(adapter, fsf_req);
3442 spin_unlock(&adapter->req_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003444 inc_seq_no = (fsf_req->qtcb != NULL);
3445
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003446 fsf_req->issued = get_clock();
3447
Swen Schillig00bab912008-06-10 18:20:57 +02003448 retval = zfcp_qdio_send(fsf_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
3450 if (unlikely(retval)) {
3451 /* Queues are down..... */
Andreas Herrmann2abbe862006-09-18 22:29:56 +02003452 del_timer(&fsf_req->timer);
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003453 spin_lock(&adapter->req_list_lock);
Heiko Carstensca2d02c2007-05-08 11:17:54 +02003454 zfcp_reqlist_remove(adapter, fsf_req);
Volker Sameskefea9d6c2006-08-02 11:05:16 +02003455 spin_unlock(&adapter->req_list_lock);
3456 /* undo changes in request queue made for this request */
Swen Schillig00bab912008-06-10 18:20:57 +02003457 atomic_add(fsf_req->sbal_number, &req_q->count);
3458 req_q->first -= fsf_req->sbal_number;
3459 req_q->first += QDIO_MAX_BUFFERS_PER_Q;
3460 req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
Martin Peschke1f6f7122008-04-18 12:51:55 +02003461 zfcp_erp_adapter_reopen(adapter, 0, 116, fsf_req);
Swen Schillig00bab912008-06-10 18:20:57 +02003462 retval = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 /*
3465 * increase FSF sequence counter -
3466 * this must only be done for request successfully enqueued to
3467 * QDIO this rejected requests may be cleaned up by calling
3468 * routines resulting in missing sequence counter values
3469 * otherwise,
3470 */
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003471
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 /* Don't increase for unsolicited status */
Maxim Shchetynin8a36e452005-09-13 21:50:38 +02003473 if (inc_seq_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 adapter->fsf_req_seq_no++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 }
3476 return retval;
3477}