diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_scsi.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 178 |
1 files changed, 26 insertions, 152 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 31a76065cf28..fffd12399010 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -414,67 +414,37 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id) | |||
414 | return (struct zfcp_port *) NULL; | 414 | return (struct zfcp_port *) NULL; |
415 | } | 415 | } |
416 | 416 | ||
417 | /* | 417 | /** |
418 | * function: zfcp_scsi_eh_abort_handler | 418 | * zfcp_scsi_eh_abort_handler - abort the specified SCSI command |
419 | * | 419 | * @scpnt: pointer to scsi_cmnd to be aborted |
420 | * purpose: tries to abort the specified (timed out) SCSI command | 420 | * Return: SUCCESS - command has been aborted and cleaned up in internal |
421 | * | 421 | * bookkeeping, SCSI stack won't be called for aborted command |
422 | * note: We do not need to care for a SCSI command which completes | 422 | * FAILED - otherwise |
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 | * | 423 | * |
430 | * returns: SUCCESS - command has been aborted and cleaned up in internal | 424 | * We do not need to care for a SCSI command which completes normally |
431 | * bookkeeping, | 425 | * but late during this abort routine runs. We are allowed to return |
432 | * SCSI stack won't be called for aborted command | 426 | * late commands to the SCSI stack. It tracks the state of commands and |
433 | * FAILED - otherwise | 427 | * will handle late commands. (Usually, the normal completion of late |
428 | * commands is ignored with respect to the running abort operation.) | ||
434 | */ | 429 | */ |
435 | int | 430 | int |
436 | __zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | 431 | zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) |
437 | { | 432 | { |
433 | struct Scsi_Host *scsi_host; | ||
434 | struct zfcp_adapter *adapter; | ||
435 | struct zfcp_unit *unit; | ||
438 | int retval = SUCCESS; | 436 | int retval = SUCCESS; |
439 | struct zfcp_fsf_req *new_fsf_req, *old_fsf_req; | 437 | 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; | 438 | unsigned long flags; |
446 | u32 status = 0; | 439 | |
447 | 440 | scsi_host = scpnt->device->host; | |
448 | /* the components of a abort_dbf record (fixed size record) */ | 441 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; |
449 | u64 dbf_scsi_cmnd = (unsigned long) scpnt; | 442 | unit = (struct zfcp_unit *) scpnt->device->hostdata; |
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 | 443 | ||
466 | ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", | 444 | ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", |
467 | scpnt, zfcp_get_busid_by_adapter(adapter)); | 445 | scpnt, zfcp_get_busid_by_adapter(adapter)); |
468 | 446 | ||
469 | spin_unlock_irq(scsi_host->host_lock); | 447 | /* avoid race condition between late normal completion and abort */ |
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); | 448 | write_lock_irqsave(&adapter->abort_lock, flags); |
479 | 449 | ||
480 | /* | 450 | /* |
@@ -484,144 +454,48 @@ __zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | |||
484 | * this routine returns. (scpnt is parameter passed to this routine | 454 | * this routine returns. (scpnt is parameter passed to this routine |
485 | * and must not disappear during abort even on late completion.) | 455 | * and must not disappear during abort even on late completion.) |
486 | */ | 456 | */ |
487 | req_data = (union zfcp_req_data *) scpnt->host_scribble; | 457 | old_fsf_req = (struct zfcp_fsf_req *) 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) { | 458 | if (!old_fsf_req) { |
511 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 459 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
512 | ZFCP_LOG_NORMAL("bug: no old fsf request found\n"); | 460 | 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"); | 461 | ZFCP_LOG_NORMAL("scsi_cmnd:\n"); |
517 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | 462 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, |
518 | (char *) scpnt, sizeof (struct scsi_cmnd)); | 463 | (char *) scpnt, sizeof (struct scsi_cmnd)); |
519 | retval = FAILED; | 464 | retval = FAILED; |
520 | strncpy(dbf_result, "##bug:r", ZFCP_ABORT_DBF_LENGTH); | ||
521 | goto out; | 465 | goto out; |
522 | } | 466 | } |
523 | old_fsf_req->data.send_fcp_command_task.scsi_cmnd = NULL; | 467 | old_fsf_req->data = 0; |
524 | /* mark old request as being aborted */ | ||
525 | old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; | 468 | 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 | 469 | ||
538 | /* | 470 | /* don't access old_fsf_req after releasing the abort_lock */ |
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); | 471 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
546 | /* call FSF routine which does the abort */ | 472 | /* call FSF routine which does the abort */ |
547 | new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req, | 473 | new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req, |
548 | adapter, unit, 0); | 474 | adapter, unit, 0); |
549 | ZFCP_LOG_DEBUG("new_fsf_req=%p\n", new_fsf_req); | ||
550 | if (!new_fsf_req) { | 475 | if (!new_fsf_req) { |
551 | retval = FAILED; | 476 | retval = FAILED; |
552 | ZFCP_LOG_NORMAL("error: initiation of Abort FCP Cmnd " | 477 | ZFCP_LOG_NORMAL("error: initiation of Abort FCP Cmnd " |
553 | "failed\n"); | 478 | "failed\n"); |
554 | strncpy(dbf_result, "##nores", ZFCP_ABORT_DBF_LENGTH); | ||
555 | goto out; | 479 | goto out; |
556 | } | 480 | } |
557 | 481 | ||
558 | /* wait for completion of abort */ | 482 | /* 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, | 483 | __wait_event(new_fsf_req->completion_wq, |
566 | new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 484 | 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_free(new_fsf_req); | 485 | zfcp_fsf_req_free(new_fsf_req); |
579 | #else | 486 | |
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 */ | 487 | /* status should be valid since signals were not permitted */ |
585 | if (status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { | 488 | if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { |
586 | retval = SUCCESS; | 489 | retval = SUCCESS; |
587 | strncpy(dbf_result, "##succ", ZFCP_ABORT_DBF_LENGTH); | 490 | } else if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { |
588 | } else if (status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { | ||
589 | retval = SUCCESS; | 491 | retval = SUCCESS; |
590 | strncpy(dbf_result, "##late2", ZFCP_ABORT_DBF_LENGTH); | ||
591 | } else { | 492 | } else { |
592 | retval = FAILED; | 493 | retval = FAILED; |
593 | strncpy(dbf_result, "##fail", ZFCP_ABORT_DBF_LENGTH); | ||
594 | } | 494 | } |
595 | |||
596 | out: | 495 | 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; | 496 | return retval; |
612 | } | 497 | } |
613 | 498 | ||
614 | int | ||
615 | zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | ||
616 | { | ||
617 | int rc; | ||
618 | struct Scsi_Host *scsi_host = scpnt->device->host; | ||
619 | spin_lock_irq(scsi_host->host_lock); | ||
620 | rc = __zfcp_scsi_eh_abort_handler(scpnt); | ||
621 | spin_unlock_irq(scsi_host->host_lock); | ||
622 | return rc; | ||
623 | } | ||
624 | |||
625 | /* | 499 | /* |
626 | * function: zfcp_scsi_eh_device_reset_handler | 500 | * function: zfcp_scsi_eh_device_reset_handler |
627 | * | 501 | * |