diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/scsi/zfcp_scsi.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/s390/scsi/zfcp_scsi.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c new file mode 100644 index 000000000000..e21b547fd427 --- /dev/null +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * | ||
3 | * linux/drivers/s390/scsi/zfcp_scsi.c | ||
4 | * | ||
5 | * FCP adapter driver for IBM eServer zSeries | ||
6 | * | ||
7 | * (C) Copyright IBM Corp. 2002, 2004 | ||
8 | * | ||
9 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | ||
10 | * Raimund Schroeder <raimund.schroeder@de.ibm.com> | ||
11 | * Aron Zeh | ||
12 | * Wolfgang Taphorn | ||
13 | * Stefan Bader <stefan.bader@de.ibm.com> | ||
14 | * Heiko Carstens <heiko.carstens@de.ibm.com> | ||
15 | * Andreas Herrmann <aherrman@de.ibm.com> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2, or (at your option) | ||
20 | * any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | */ | ||
31 | |||
32 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI | ||
33 | |||
34 | #define ZFCP_SCSI_REVISION "$Revision: 1.74 $" | ||
35 | |||
36 | #include "zfcp_ext.h" | ||
37 | |||
38 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); | ||
39 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); | ||
40 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp); | ||
41 | static int zfcp_scsi_queuecommand(struct scsi_cmnd *, | ||
42 | void (*done) (struct scsi_cmnd *)); | ||
43 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *); | ||
44 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *); | ||
45 | static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *); | ||
46 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *); | ||
47 | static int zfcp_task_management_function(struct zfcp_unit *, u8); | ||
48 | |||
49 | static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t, | ||
50 | scsi_lun_t); | ||
51 | static struct zfcp_port *zfcp_port_lookup(struct zfcp_adapter *, int, | ||
52 | scsi_id_t); | ||
53 | |||
54 | static struct device_attribute *zfcp_sysfs_sdev_attrs[]; | ||
55 | |||
56 | struct scsi_transport_template *zfcp_transport_template; | ||
57 | |||
58 | struct zfcp_data zfcp_data = { | ||
59 | .scsi_host_template = { | ||
60 | name: ZFCP_NAME, | ||
61 | proc_name: "zfcp", | ||
62 | proc_info: NULL, | ||
63 | detect: NULL, | ||
64 | slave_alloc: zfcp_scsi_slave_alloc, | ||
65 | slave_configure: zfcp_scsi_slave_configure, | ||
66 | slave_destroy: zfcp_scsi_slave_destroy, | ||
67 | queuecommand: zfcp_scsi_queuecommand, | ||
68 | eh_abort_handler: zfcp_scsi_eh_abort_handler, | ||
69 | eh_device_reset_handler: zfcp_scsi_eh_device_reset_handler, | ||
70 | eh_bus_reset_handler: zfcp_scsi_eh_bus_reset_handler, | ||
71 | eh_host_reset_handler: zfcp_scsi_eh_host_reset_handler, | ||
72 | /* FIXME(openfcp): Tune */ | ||
73 | can_queue: 4096, | ||
74 | this_id: 0, | ||
75 | /* | ||
76 | * FIXME: | ||
77 | * one less? can zfcp_create_sbale cope with it? | ||
78 | */ | ||
79 | sg_tablesize: ZFCP_MAX_SBALES_PER_REQ, | ||
80 | cmd_per_lun: 1, | ||
81 | unchecked_isa_dma: 0, | ||
82 | use_clustering: 1, | ||
83 | sdev_attrs: zfcp_sysfs_sdev_attrs, | ||
84 | }, | ||
85 | .driver_version = ZFCP_VERSION, | ||
86 | /* rest initialised with zeros */ | ||
87 | }; | ||
88 | |||
89 | /* Find start of Response Information in FCP response unit*/ | ||
90 | char * | ||
91 | zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | ||
92 | { | ||
93 | char *fcp_rsp_info_ptr; | ||
94 | |||
95 | fcp_rsp_info_ptr = | ||
96 | (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); | ||
97 | |||
98 | return fcp_rsp_info_ptr; | ||
99 | } | ||
100 | |||
101 | /* Find start of Sense Information in FCP response unit*/ | ||
102 | char * | ||
103 | zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | ||
104 | { | ||
105 | char *fcp_sns_info_ptr; | ||
106 | |||
107 | fcp_sns_info_ptr = | ||
108 | (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); | ||
109 | if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) | ||
110 | fcp_sns_info_ptr = (char *) fcp_sns_info_ptr + | ||
111 | fcp_rsp_iu->fcp_rsp_len; | ||
112 | |||
113 | return fcp_sns_info_ptr; | ||
114 | } | ||
115 | |||
116 | fcp_dl_t * | ||
117 | zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) | ||
118 | { | ||
119 | int additional_length = fcp_cmd->add_fcp_cdb_length << 2; | ||
120 | fcp_dl_t *fcp_dl_addr; | ||
121 | |||
122 | fcp_dl_addr = (fcp_dl_t *) | ||
123 | ((unsigned char *) fcp_cmd + | ||
124 | sizeof (struct fcp_cmnd_iu) + additional_length); | ||
125 | /* | ||
126 | * fcp_dl_addr = start address of fcp_cmnd structure + | ||
127 | * size of fixed part + size of dynamically sized add_dcp_cdb field | ||
128 | * SEE FCP-2 documentation | ||
129 | */ | ||
130 | return fcp_dl_addr; | ||
131 | } | ||
132 | |||
133 | fcp_dl_t | ||
134 | zfcp_get_fcp_dl(struct fcp_cmnd_iu * fcp_cmd) | ||
135 | { | ||
136 | return *zfcp_get_fcp_dl_ptr(fcp_cmd); | ||
137 | } | ||
138 | |||
139 | void | ||
140 | zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) | ||
141 | { | ||
142 | *zfcp_get_fcp_dl_ptr(fcp_cmd) = fcp_dl; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * note: it's a bit-or operation not an assignment | ||
147 | * regarding the specified byte | ||
148 | */ | ||
149 | static inline void | ||
150 | set_byte(u32 * result, char status, char pos) | ||
151 | { | ||
152 | *result |= status << (pos * 8); | ||
153 | } | ||
154 | |||
155 | void | ||
156 | set_host_byte(u32 * result, char status) | ||
157 | { | ||
158 | set_byte(result, status, 2); | ||
159 | } | ||
160 | |||
161 | void | ||
162 | set_driver_byte(u32 * result, char status) | ||
163 | { | ||
164 | set_byte(result, status, 3); | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * function: zfcp_scsi_slave_alloc | ||
169 | * | ||
170 | * purpose: | ||
171 | * | ||
172 | * returns: | ||
173 | */ | ||
174 | |||
175 | static int | ||
176 | zfcp_scsi_slave_alloc(struct scsi_device *sdp) | ||
177 | { | ||
178 | struct zfcp_adapter *adapter; | ||
179 | struct zfcp_unit *unit; | ||
180 | unsigned long flags; | ||
181 | int retval = -ENODEV; | ||
182 | |||
183 | adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; | ||
184 | if (!adapter) | ||
185 | goto out; | ||
186 | |||
187 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
188 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); | ||
189 | if (unit) { | ||
190 | sdp->hostdata = unit; | ||
191 | unit->device = sdp; | ||
192 | zfcp_unit_get(unit); | ||
193 | retval = 0; | ||
194 | } | ||
195 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
196 | out: | ||
197 | return retval; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * function: zfcp_scsi_slave_destroy | ||
202 | * | ||
203 | * purpose: | ||
204 | * | ||
205 | * returns: | ||
206 | */ | ||
207 | |||
208 | static void | ||
209 | zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | ||
210 | { | ||
211 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | ||
212 | |||
213 | if (unit) { | ||
214 | sdpnt->hostdata = NULL; | ||
215 | unit->device = NULL; | ||
216 | zfcp_unit_put(unit); | ||
217 | } else { | ||
218 | ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at " | ||
219 | "address %p\n", sdpnt); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * called from scsi midlayer to allow finetuning of a device. | ||
225 | */ | ||
226 | static int | ||
227 | zfcp_scsi_slave_configure(struct scsi_device *sdp) | ||
228 | { | ||
229 | if (sdp->tagged_supported) | ||
230 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, ZFCP_CMND_PER_LUN); | ||
231 | else | ||
232 | scsi_adjust_queue_depth(sdp, 0, 1); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function | ||
238 | * @scpnt: pointer to struct scsi_cmnd where result is set | ||
239 | * @result: result to be set in scpnt (e.g. DID_ERROR) | ||
240 | */ | ||
241 | static void | ||
242 | zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) | ||
243 | { | ||
244 | set_host_byte(&scpnt->result, result); | ||
245 | zfcp_cmd_dbf_event_scsi("failing", scpnt); | ||
246 | /* return directly */ | ||
247 | scpnt->scsi_done(scpnt); | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and | ||
252 | * zfcp_scsi_command_sync | ||
253 | * @adapter: adapter where scsi command is issued | ||
254 | * @unit: unit to which scsi command is sent | ||
255 | * @scpnt: scsi command to be sent | ||
256 | * @timer: timer to be started if request is successfully initiated | ||
257 | * | ||
258 | * Note: In scsi_done function must be set in scpnt. | ||
259 | */ | ||
260 | int | ||
261 | zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, | ||
262 | struct scsi_cmnd *scpnt, struct timer_list *timer) | ||
263 | { | ||
264 | int tmp; | ||
265 | int retval; | ||
266 | |||
267 | retval = 0; | ||
268 | |||
269 | BUG_ON((adapter == NULL) || (adapter != unit->port->adapter)); | ||
270 | BUG_ON(scpnt->scsi_done == NULL); | ||
271 | |||
272 | if (unlikely(NULL == unit)) { | ||
273 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
274 | goto out; | ||
275 | } | ||
276 | |||
277 | if (unlikely( | ||
278 | atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || | ||
279 | !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) { | ||
280 | ZFCP_LOG_DEBUG("stopping SCSI I/O on unit 0x%016Lx on port " | ||
281 | "0x%016Lx on adapter %s\n", | ||
282 | unit->fcp_lun, unit->port->wwpn, | ||
283 | zfcp_get_busid_by_adapter(adapter)); | ||
284 | zfcp_scsi_command_fail(scpnt, DID_ERROR); | ||
285 | goto out; | ||
286 | } | ||
287 | |||
288 | if (unlikely( | ||
289 | !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) { | ||
290 | ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx " | ||
291 | "on port 0x%016Lx in recovery\n", | ||
292 | zfcp_get_busid_by_unit(unit), | ||
293 | unit->fcp_lun, unit->port->wwpn); | ||
294 | retval = SCSI_MLQUEUE_DEVICE_BUSY; | ||
295 | goto out; | ||
296 | } | ||
297 | |||
298 | tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, timer, | ||
299 | ZFCP_REQ_AUTO_CLEANUP); | ||
300 | |||
301 | if (unlikely(tmp < 0)) { | ||
302 | ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); | ||
303 | retval = SCSI_MLQUEUE_HOST_BUSY; | ||
304 | } | ||
305 | |||
306 | out: | ||
307 | return retval; | ||
308 | } | ||
309 | |||
310 | void | ||
311 | zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) | ||
312 | { | ||
313 | struct completion *wait = (struct completion *) scpnt->SCp.ptr; | ||
314 | complete(wait); | ||
315 | } | ||
316 | |||
317 | |||
318 | /** | ||
319 | * zfcp_scsi_command_sync - send a SCSI command and wait for completion | ||
320 | * @unit: unit where command is sent to | ||
321 | * @scpnt: scsi command to be sent | ||
322 | * @timer: timer to be started if request is successfully initiated | ||
323 | * Return: 0 | ||
324 | * | ||
325 | * Errors are indicated in scpnt->result | ||
326 | */ | ||
327 | int | ||
328 | zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, | ||
329 | struct timer_list *timer) | ||
330 | { | ||
331 | int ret; | ||
332 | DECLARE_COMPLETION(wait); | ||
333 | |||
334 | scpnt->SCp.ptr = (void *) &wait; /* silent re-use */ | ||
335 | scpnt->scsi_done = zfcp_scsi_command_sync_handler; | ||
336 | ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, timer); | ||
337 | if (ret == 0) | ||
338 | wait_for_completion(&wait); | ||
339 | |||
340 | scpnt->SCp.ptr = NULL; | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * function: zfcp_scsi_queuecommand | ||
347 | * | ||
348 | * purpose: enqueues a SCSI command to the specified target device | ||
349 | * | ||
350 | * returns: 0 - success, SCSI command enqueued | ||
351 | * !0 - failure | ||
352 | */ | ||
353 | int | ||
354 | zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | ||
355 | void (*done) (struct scsi_cmnd *)) | ||
356 | { | ||
357 | struct zfcp_unit *unit; | ||
358 | struct zfcp_adapter *adapter; | ||
359 | |||
360 | /* reset the status for this request */ | ||
361 | scpnt->result = 0; | ||
362 | scpnt->host_scribble = NULL; | ||
363 | scpnt->scsi_done = done; | ||
364 | |||
365 | /* | ||
366 | * figure out adapter and target device | ||
367 | * (stored there by zfcp_scsi_slave_alloc) | ||
368 | */ | ||
369 | adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; | ||
370 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | ||
371 | |||
372 | return zfcp_scsi_command_async(adapter, unit, scpnt, NULL); | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * function: zfcp_unit_lookup | ||
377 | * | ||
378 | * purpose: | ||
379 | * | ||
380 | * returns: | ||
381 | * | ||
382 | * context: | ||
383 | */ | ||
384 | static struct zfcp_unit * | ||
385 | zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id, | ||
386 | scsi_lun_t lun) | ||
387 | { | ||
388 | struct zfcp_port *port; | ||
389 | struct zfcp_unit *unit, *retval = NULL; | ||
390 | |||
391 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
392 | if (id != port->scsi_id) | ||
393 | continue; | ||
394 | list_for_each_entry(unit, &port->unit_list_head, list) { | ||
395 | if (lun == unit->scsi_lun) { | ||
396 | retval = unit; | ||
397 | goto out; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | out: | ||
402 | return retval; | ||
403 | } | ||
404 | |||
405 | static struct zfcp_port * | ||
406 | zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id) | ||
407 | { | ||
408 | struct zfcp_port *port; | ||
409 | |||
410 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
411 | if (id == port->scsi_id) | ||
412 | return port; | ||
413 | } | ||
414 | return (struct zfcp_port *) NULL; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * function: zfcp_scsi_eh_abort_handler | ||
419 | * | ||
420 | * purpose: tries to abort the specified (timed out) SCSI command | ||
421 | * | ||
422 | * note: We do not need to care for a SCSI command which completes | ||
423 | * normally but late during this abort routine runs. | ||
424 | * We are allowed to return late commands to the SCSI stack. | ||
425 | * It tracks the state of commands and will handle late commands. | ||
426 | * (Usually, the normal completion of late commands is ignored with | ||
427 | * respect to the running abort operation. Grep for 'done_late' | ||
428 | * in the SCSI stacks sources.) | ||
429 | * | ||
430 | * returns: SUCCESS - command has been aborted and cleaned up in internal | ||
431 | * bookkeeping, | ||
432 | * SCSI stack won't be called for aborted command | ||
433 | * FAILED - otherwise | ||
434 | */ | ||
435 | int | ||
436 | zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | ||
437 | { | ||
438 | int retval = SUCCESS; | ||
439 | struct zfcp_fsf_req *new_fsf_req, *old_fsf_req; | ||
440 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; | ||
441 | struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata; | ||
442 | struct zfcp_port *port = unit->port; | ||
443 | struct Scsi_Host *scsi_host = scpnt->device->host; | ||
444 | union zfcp_req_data *req_data = NULL; | ||
445 | unsigned long flags; | ||
446 | u32 status = 0; | ||
447 | |||
448 | /* the components of a abort_dbf record (fixed size record) */ | ||
449 | u64 dbf_scsi_cmnd = (unsigned long) scpnt; | ||
450 | char dbf_opcode[ZFCP_ABORT_DBF_LENGTH]; | ||
451 | wwn_t dbf_wwn = port->wwpn; | ||
452 | fcp_lun_t dbf_fcp_lun = unit->fcp_lun; | ||
453 | u64 dbf_retries = scpnt->retries; | ||
454 | u64 dbf_allowed = scpnt->allowed; | ||
455 | u64 dbf_timeout = 0; | ||
456 | u64 dbf_fsf_req = 0; | ||
457 | u64 dbf_fsf_status = 0; | ||
458 | u64 dbf_fsf_qual[2] = { 0, 0 }; | ||
459 | char dbf_result[ZFCP_ABORT_DBF_LENGTH] = "##undef"; | ||
460 | |||
461 | memset(dbf_opcode, 0, ZFCP_ABORT_DBF_LENGTH); | ||
462 | memcpy(dbf_opcode, | ||
463 | scpnt->cmnd, | ||
464 | min(scpnt->cmd_len, (unsigned char) ZFCP_ABORT_DBF_LENGTH)); | ||
465 | |||
466 | ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", | ||
467 | scpnt, zfcp_get_busid_by_adapter(adapter)); | ||
468 | |||
469 | spin_unlock_irq(scsi_host->host_lock); | ||
470 | |||
471 | /* | ||
472 | * Race condition between normal (late) completion and abort has | ||
473 | * to be avoided. | ||
474 | * The entirity of all accesses to scsi_req have to be atomic. | ||
475 | * scsi_req is usually part of the fsf_req and thus we block the | ||
476 | * release of fsf_req as long as we need to access scsi_req. | ||
477 | */ | ||
478 | write_lock_irqsave(&adapter->abort_lock, flags); | ||
479 | |||
480 | /* | ||
481 | * Check whether command has just completed and can not be aborted. | ||
482 | * Even if the command has just been completed late, we can access | ||
483 | * scpnt since the SCSI stack does not release it at least until | ||
484 | * this routine returns. (scpnt is parameter passed to this routine | ||
485 | * and must not disappear during abort even on late completion.) | ||
486 | */ | ||
487 | req_data = (union zfcp_req_data *) scpnt->host_scribble; | ||
488 | /* DEBUG */ | ||
489 | ZFCP_LOG_DEBUG("req_data=%p\n", req_data); | ||
490 | if (!req_data) { | ||
491 | ZFCP_LOG_DEBUG("late command completion overtook abort\n"); | ||
492 | /* | ||
493 | * That's it. | ||
494 | * Do not initiate abort but return SUCCESS. | ||
495 | */ | ||
496 | write_unlock_irqrestore(&adapter->abort_lock, flags); | ||
497 | retval = SUCCESS; | ||
498 | strncpy(dbf_result, "##late1", ZFCP_ABORT_DBF_LENGTH); | ||
499 | goto out; | ||
500 | } | ||
501 | |||
502 | /* Figure out which fsf_req needs to be aborted. */ | ||
503 | old_fsf_req = req_data->send_fcp_command_task.fsf_req; | ||
504 | |||
505 | dbf_fsf_req = (unsigned long) old_fsf_req; | ||
506 | dbf_timeout = | ||
507 | (jiffies - req_data->send_fcp_command_task.start_jiffies) / HZ; | ||
508 | |||
509 | ZFCP_LOG_DEBUG("old_fsf_req=%p\n", old_fsf_req); | ||
510 | if (!old_fsf_req) { | ||
511 | write_unlock_irqrestore(&adapter->abort_lock, flags); | ||
512 | ZFCP_LOG_NORMAL("bug: no old fsf request found\n"); | ||
513 | ZFCP_LOG_NORMAL("req_data:\n"); | ||
514 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | ||
515 | (char *) req_data, sizeof (union zfcp_req_data)); | ||
516 | ZFCP_LOG_NORMAL("scsi_cmnd:\n"); | ||
517 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | ||
518 | (char *) scpnt, sizeof (struct scsi_cmnd)); | ||
519 | retval = FAILED; | ||
520 | strncpy(dbf_result, "##bug:r", ZFCP_ABORT_DBF_LENGTH); | ||
521 | goto out; | ||
522 | } | ||
523 | old_fsf_req->data.send_fcp_command_task.scsi_cmnd = NULL; | ||
524 | /* mark old request as being aborted */ | ||
525 | old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; | ||
526 | /* | ||
527 | * We have to collect all information (e.g. unit) needed by | ||
528 | * zfcp_fsf_abort_fcp_command before calling that routine | ||
529 | * since that routine is not allowed to access | ||
530 | * fsf_req which it is going to abort. | ||
531 | * This is because of we need to release fsf_req_list_lock | ||
532 | * before calling zfcp_fsf_abort_fcp_command. | ||
533 | * Since this lock will not be held, fsf_req may complete | ||
534 | * late and may be released meanwhile. | ||
535 | */ | ||
536 | ZFCP_LOG_DEBUG("unit 0x%016Lx (%p)\n", unit->fcp_lun, unit); | ||
537 | |||
538 | /* | ||
539 | * We block (call schedule) | ||
540 | * That's why we must release the lock and enable the | ||
541 | * interrupts before. | ||
542 | * On the other hand we do not need the lock anymore since | ||
543 | * all critical accesses to scsi_req are done. | ||
544 | */ | ||
545 | write_unlock_irqrestore(&adapter->abort_lock, flags); | ||
546 | /* call FSF routine which does the abort */ | ||
547 | new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req, | ||
548 | adapter, unit, 0); | ||
549 | ZFCP_LOG_DEBUG("new_fsf_req=%p\n", new_fsf_req); | ||
550 | if (!new_fsf_req) { | ||
551 | retval = FAILED; | ||
552 | ZFCP_LOG_NORMAL("error: initiation of Abort FCP Cmnd " | ||
553 | "failed\n"); | ||
554 | strncpy(dbf_result, "##nores", ZFCP_ABORT_DBF_LENGTH); | ||
555 | goto out; | ||
556 | } | ||
557 | |||
558 | /* wait for completion of abort */ | ||
559 | ZFCP_LOG_DEBUG("waiting for cleanup...\n"); | ||
560 | #if 1 | ||
561 | /* | ||
562 | * FIXME: | ||
563 | * copying zfcp_fsf_req_wait_and_cleanup code is not really nice | ||
564 | */ | ||
565 | __wait_event(new_fsf_req->completion_wq, | ||
566 | new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
567 | status = new_fsf_req->status; | ||
568 | dbf_fsf_status = new_fsf_req->qtcb->header.fsf_status; | ||
569 | /* | ||
570 | * Ralphs special debug load provides timestamps in the FSF | ||
571 | * status qualifier. This might be specified later if being | ||
572 | * useful for debugging aborts. | ||
573 | */ | ||
574 | dbf_fsf_qual[0] = | ||
575 | *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[0]; | ||
576 | dbf_fsf_qual[1] = | ||
577 | *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[2]; | ||
578 | zfcp_fsf_req_cleanup(new_fsf_req); | ||
579 | #else | ||
580 | retval = zfcp_fsf_req_wait_and_cleanup(new_fsf_req, | ||
581 | ZFCP_UNINTERRUPTIBLE, &status); | ||
582 | #endif | ||
583 | ZFCP_LOG_DEBUG("Waiting for cleanup complete, status=0x%x\n", status); | ||
584 | /* status should be valid since signals were not permitted */ | ||
585 | if (status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { | ||
586 | retval = SUCCESS; | ||
587 | strncpy(dbf_result, "##succ", ZFCP_ABORT_DBF_LENGTH); | ||
588 | } else if (status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { | ||
589 | retval = SUCCESS; | ||
590 | strncpy(dbf_result, "##late2", ZFCP_ABORT_DBF_LENGTH); | ||
591 | } else { | ||
592 | retval = FAILED; | ||
593 | strncpy(dbf_result, "##fail", ZFCP_ABORT_DBF_LENGTH); | ||
594 | } | ||
595 | |||
596 | out: | ||
597 | debug_event(adapter->abort_dbf, 1, &dbf_scsi_cmnd, sizeof (u64)); | ||
598 | debug_event(adapter->abort_dbf, 1, &dbf_opcode, ZFCP_ABORT_DBF_LENGTH); | ||
599 | debug_event(adapter->abort_dbf, 1, &dbf_wwn, sizeof (wwn_t)); | ||
600 | debug_event(adapter->abort_dbf, 1, &dbf_fcp_lun, sizeof (fcp_lun_t)); | ||
601 | debug_event(adapter->abort_dbf, 1, &dbf_retries, sizeof (u64)); | ||
602 | debug_event(adapter->abort_dbf, 1, &dbf_allowed, sizeof (u64)); | ||
603 | debug_event(adapter->abort_dbf, 1, &dbf_timeout, sizeof (u64)); | ||
604 | debug_event(adapter->abort_dbf, 1, &dbf_fsf_req, sizeof (u64)); | ||
605 | debug_event(adapter->abort_dbf, 1, &dbf_fsf_status, sizeof (u64)); | ||
606 | debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[0], sizeof (u64)); | ||
607 | debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[1], sizeof (u64)); | ||
608 | debug_text_event(adapter->abort_dbf, 1, dbf_result); | ||
609 | |||
610 | spin_lock_irq(scsi_host->host_lock); | ||
611 | return retval; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * function: zfcp_scsi_eh_device_reset_handler | ||
616 | * | ||
617 | * purpose: | ||
618 | * | ||
619 | * returns: | ||
620 | */ | ||
621 | int | ||
622 | zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) | ||
623 | { | ||
624 | int retval; | ||
625 | struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata; | ||
626 | struct Scsi_Host *scsi_host = scpnt->device->host; | ||
627 | |||
628 | spin_unlock_irq(scsi_host->host_lock); | ||
629 | |||
630 | if (!unit) { | ||
631 | ZFCP_LOG_NORMAL("bug: Tried reset for nonexistent unit\n"); | ||
632 | retval = SUCCESS; | ||
633 | goto out; | ||
634 | } | ||
635 | ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun); | ||
636 | |||
637 | /* | ||
638 | * If we do not know whether the unit supports 'logical unit reset' | ||
639 | * then try 'logical unit reset' and proceed with 'target reset' | ||
640 | * if 'logical unit reset' fails. | ||
641 | * If the unit is known not to support 'logical unit reset' then | ||
642 | * skip 'logical unit reset' and try 'target reset' immediately. | ||
643 | */ | ||
644 | if (!atomic_test_mask(ZFCP_STATUS_UNIT_NOTSUPPUNITRESET, | ||
645 | &unit->status)) { | ||
646 | retval = | ||
647 | zfcp_task_management_function(unit, FCP_LOGICAL_UNIT_RESET); | ||
648 | if (retval) { | ||
649 | ZFCP_LOG_DEBUG("unit reset failed (unit=%p)\n", unit); | ||
650 | if (retval == -ENOTSUPP) | ||
651 | atomic_set_mask | ||
652 | (ZFCP_STATUS_UNIT_NOTSUPPUNITRESET, | ||
653 | &unit->status); | ||
654 | /* fall through and try 'target reset' next */ | ||
655 | } else { | ||
656 | ZFCP_LOG_DEBUG("unit reset succeeded (unit=%p)\n", | ||
657 | unit); | ||
658 | /* avoid 'target reset' */ | ||
659 | retval = SUCCESS; | ||
660 | goto out; | ||
661 | } | ||
662 | } | ||
663 | retval = zfcp_task_management_function(unit, FCP_TARGET_RESET); | ||
664 | if (retval) { | ||
665 | ZFCP_LOG_DEBUG("target reset failed (unit=%p)\n", unit); | ||
666 | retval = FAILED; | ||
667 | } else { | ||
668 | ZFCP_LOG_DEBUG("target reset succeeded (unit=%p)\n", unit); | ||
669 | retval = SUCCESS; | ||
670 | } | ||
671 | out: | ||
672 | spin_lock_irq(scsi_host->host_lock); | ||
673 | return retval; | ||
674 | } | ||
675 | |||
676 | static int | ||
677 | zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags) | ||
678 | { | ||
679 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
680 | int retval; | ||
681 | int status; | ||
682 | struct zfcp_fsf_req *fsf_req; | ||
683 | |||
684 | /* issue task management function */ | ||
685 | fsf_req = zfcp_fsf_send_fcp_command_task_management | ||
686 | (adapter, unit, tm_flags, 0); | ||
687 | if (!fsf_req) { | ||
688 | ZFCP_LOG_INFO("error: creation of task management request " | ||
689 | "failed for unit 0x%016Lx on port 0x%016Lx on " | ||
690 | "adapter %s\n", unit->fcp_lun, unit->port->wwpn, | ||
691 | zfcp_get_busid_by_adapter(adapter)); | ||
692 | retval = -ENOMEM; | ||
693 | goto out; | ||
694 | } | ||
695 | |||
696 | retval = zfcp_fsf_req_wait_and_cleanup(fsf_req, | ||
697 | ZFCP_UNINTERRUPTIBLE, &status); | ||
698 | /* | ||
699 | * check completion status of task management function | ||
700 | * (status should always be valid since no signals permitted) | ||
701 | */ | ||
702 | if (status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) | ||
703 | retval = -EIO; | ||
704 | else if (status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) | ||
705 | retval = -ENOTSUPP; | ||
706 | else | ||
707 | retval = 0; | ||
708 | out: | ||
709 | return retval; | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * function: zfcp_scsi_eh_bus_reset_handler | ||
714 | * | ||
715 | * purpose: | ||
716 | * | ||
717 | * returns: | ||
718 | */ | ||
719 | int | ||
720 | zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt) | ||
721 | { | ||
722 | int retval = 0; | ||
723 | struct zfcp_unit *unit; | ||
724 | struct Scsi_Host *scsi_host = scpnt->device->host; | ||
725 | |||
726 | spin_unlock_irq(scsi_host->host_lock); | ||
727 | |||
728 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | ||
729 | ZFCP_LOG_NORMAL("bus reset because of problems with " | ||
730 | "unit 0x%016Lx\n", unit->fcp_lun); | ||
731 | zfcp_erp_adapter_reopen(unit->port->adapter, 0); | ||
732 | zfcp_erp_wait(unit->port->adapter); | ||
733 | retval = SUCCESS; | ||
734 | |||
735 | spin_lock_irq(scsi_host->host_lock); | ||
736 | return retval; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * function: zfcp_scsi_eh_host_reset_handler | ||
741 | * | ||
742 | * purpose: | ||
743 | * | ||
744 | * returns: | ||
745 | */ | ||
746 | int | ||
747 | zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) | ||
748 | { | ||
749 | int retval = 0; | ||
750 | struct zfcp_unit *unit; | ||
751 | struct Scsi_Host *scsi_host = scpnt->device->host; | ||
752 | |||
753 | spin_unlock_irq(scsi_host->host_lock); | ||
754 | |||
755 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | ||
756 | ZFCP_LOG_NORMAL("host reset because of problems with " | ||
757 | "unit 0x%016Lx\n", unit->fcp_lun); | ||
758 | zfcp_erp_adapter_reopen(unit->port->adapter, 0); | ||
759 | zfcp_erp_wait(unit->port->adapter); | ||
760 | retval = SUCCESS; | ||
761 | |||
762 | spin_lock_irq(scsi_host->host_lock); | ||
763 | return retval; | ||
764 | } | ||
765 | |||
766 | /* | ||
767 | * function: | ||
768 | * | ||
769 | * purpose: | ||
770 | * | ||
771 | * returns: | ||
772 | */ | ||
773 | int | ||
774 | zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) | ||
775 | { | ||
776 | int retval = 0; | ||
777 | static unsigned int unique_id = 0; | ||
778 | |||
779 | /* register adapter as SCSI host with mid layer of SCSI stack */ | ||
780 | adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, | ||
781 | sizeof (struct zfcp_adapter *)); | ||
782 | if (!adapter->scsi_host) { | ||
783 | ZFCP_LOG_NORMAL("error: registration with SCSI stack failed " | ||
784 | "for adapter %s ", | ||
785 | zfcp_get_busid_by_adapter(adapter)); | ||
786 | retval = -EIO; | ||
787 | goto out; | ||
788 | } | ||
789 | ZFCP_LOG_DEBUG("host registered, scsi_host=%p\n", adapter->scsi_host); | ||
790 | |||
791 | /* tell the SCSI stack some characteristics of this adapter */ | ||
792 | adapter->scsi_host->max_id = 1; | ||
793 | adapter->scsi_host->max_lun = 1; | ||
794 | adapter->scsi_host->max_channel = 0; | ||
795 | adapter->scsi_host->unique_id = unique_id++; /* FIXME */ | ||
796 | adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH; | ||
797 | adapter->scsi_host->transportt = zfcp_transport_template; | ||
798 | /* | ||
799 | * Reverse mapping of the host number to avoid race condition | ||
800 | */ | ||
801 | adapter->scsi_host_no = adapter->scsi_host->host_no; | ||
802 | |||
803 | /* | ||
804 | * save a pointer to our own adapter data structure within | ||
805 | * hostdata field of SCSI host data structure | ||
806 | */ | ||
807 | adapter->scsi_host->hostdata[0] = (unsigned long) adapter; | ||
808 | |||
809 | if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { | ||
810 | scsi_host_put(adapter->scsi_host); | ||
811 | retval = -EIO; | ||
812 | goto out; | ||
813 | } | ||
814 | atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); | ||
815 | out: | ||
816 | return retval; | ||
817 | } | ||
818 | |||
819 | /* | ||
820 | * function: | ||
821 | * | ||
822 | * purpose: | ||
823 | * | ||
824 | * returns: | ||
825 | */ | ||
826 | void | ||
827 | zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | ||
828 | { | ||
829 | struct Scsi_Host *shost; | ||
830 | |||
831 | shost = adapter->scsi_host; | ||
832 | if (!shost) | ||
833 | return; | ||
834 | scsi_remove_host(shost); | ||
835 | scsi_host_put(shost); | ||
836 | adapter->scsi_host = NULL; | ||
837 | adapter->scsi_host_no = 0; | ||
838 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); | ||
839 | |||
840 | return; | ||
841 | } | ||
842 | |||
843 | |||
844 | void | ||
845 | zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter) | ||
846 | { | ||
847 | adapter->scsi_er_timer.function = zfcp_fsf_scsi_er_timeout_handler; | ||
848 | adapter->scsi_er_timer.data = (unsigned long) adapter; | ||
849 | adapter->scsi_er_timer.expires = jiffies + ZFCP_SCSI_ER_TIMEOUT; | ||
850 | add_timer(&adapter->scsi_er_timer); | ||
851 | } | ||
852 | |||
853 | /* | ||
854 | * Support functions for FC transport class | ||
855 | */ | ||
856 | static void | ||
857 | zfcp_get_port_id(struct scsi_target *starget) | ||
858 | { | ||
859 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
860 | struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
861 | struct zfcp_port *port; | ||
862 | unsigned long flags; | ||
863 | |||
864 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
865 | port = zfcp_port_lookup(adapter, starget->channel, starget->id); | ||
866 | if (port) | ||
867 | fc_starget_port_id(starget) = port->d_id; | ||
868 | else | ||
869 | fc_starget_port_id(starget) = -1; | ||
870 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
871 | } | ||
872 | |||
873 | static void | ||
874 | zfcp_get_port_name(struct scsi_target *starget) | ||
875 | { | ||
876 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
877 | struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
878 | struct zfcp_port *port; | ||
879 | unsigned long flags; | ||
880 | |||
881 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
882 | port = zfcp_port_lookup(adapter, starget->channel, starget->id); | ||
883 | if (port) | ||
884 | fc_starget_port_name(starget) = port->wwpn; | ||
885 | else | ||
886 | fc_starget_port_name(starget) = -1; | ||
887 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
888 | } | ||
889 | |||
890 | static void | ||
891 | zfcp_get_node_name(struct scsi_target *starget) | ||
892 | { | ||
893 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
894 | struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
895 | struct zfcp_port *port; | ||
896 | unsigned long flags; | ||
897 | |||
898 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
899 | port = zfcp_port_lookup(adapter, starget->channel, starget->id); | ||
900 | if (port) | ||
901 | fc_starget_node_name(starget) = port->wwnn; | ||
902 | else | ||
903 | fc_starget_node_name(starget) = -1; | ||
904 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
905 | } | ||
906 | |||
907 | struct fc_function_template zfcp_transport_functions = { | ||
908 | .get_starget_port_id = zfcp_get_port_id, | ||
909 | .get_starget_port_name = zfcp_get_port_name, | ||
910 | .get_starget_node_name = zfcp_get_node_name, | ||
911 | .show_starget_port_id = 1, | ||
912 | .show_starget_port_name = 1, | ||
913 | .show_starget_node_name = 1, | ||
914 | }; | ||
915 | |||
916 | /** | ||
917 | * ZFCP_DEFINE_SCSI_ATTR | ||
918 | * @_name: name of show attribute | ||
919 | * @_format: format string | ||
920 | * @_value: value to print | ||
921 | * | ||
922 | * Generates attribute for a unit. | ||
923 | */ | ||
924 | #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ | ||
925 | static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ | ||
926 | char *buf) \ | ||
927 | { \ | ||
928 | struct scsi_device *sdev; \ | ||
929 | struct zfcp_unit *unit; \ | ||
930 | \ | ||
931 | sdev = to_scsi_device(dev); \ | ||
932 | unit = sdev->hostdata; \ | ||
933 | return sprintf(buf, _format, _value); \ | ||
934 | } \ | ||
935 | \ | ||
936 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); | ||
937 | |||
938 | ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", zfcp_get_busid_by_unit(unit)); | ||
939 | ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); | ||
940 | ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); | ||
941 | |||
942 | static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { | ||
943 | &dev_attr_fcp_lun, | ||
944 | &dev_attr_wwpn, | ||
945 | &dev_attr_hba_id, | ||
946 | NULL | ||
947 | }; | ||
948 | |||
949 | #undef ZFCP_LOG_AREA | ||