diff options
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r-- | drivers/scsi/scsi_error.c | 210 |
1 files changed, 89 insertions, 121 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6683d596234a..6a5b731bd5ba 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -460,19 +460,67 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) | |||
460 | * Return value: | 460 | * Return value: |
461 | * SUCCESS or FAILED or NEEDS_RETRY | 461 | * SUCCESS or FAILED or NEEDS_RETRY |
462 | **/ | 462 | **/ |
463 | static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) | 463 | static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense) |
464 | { | 464 | { |
465 | struct scsi_device *sdev = scmd->device; | 465 | struct scsi_device *sdev = scmd->device; |
466 | struct Scsi_Host *shost = sdev->host; | 466 | struct Scsi_Host *shost = sdev->host; |
467 | int old_result = scmd->result; | ||
467 | DECLARE_COMPLETION(done); | 468 | DECLARE_COMPLETION(done); |
468 | unsigned long timeleft; | 469 | unsigned long timeleft; |
469 | unsigned long flags; | 470 | unsigned long flags; |
471 | unsigned char old_cmnd[MAX_COMMAND_SIZE]; | ||
472 | enum dma_data_direction old_data_direction; | ||
473 | unsigned short old_use_sg; | ||
474 | unsigned char old_cmd_len; | ||
475 | unsigned old_bufflen; | ||
476 | void *old_buffer; | ||
470 | int rtn; | 477 | int rtn; |
471 | 478 | ||
479 | /* | ||
480 | * We need saved copies of a number of fields - this is because | ||
481 | * error handling may need to overwrite these with different values | ||
482 | * to run different commands, and once error handling is complete, | ||
483 | * we will need to restore these values prior to running the actual | ||
484 | * command. | ||
485 | */ | ||
486 | old_buffer = scmd->request_buffer; | ||
487 | old_bufflen = scmd->request_bufflen; | ||
488 | memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd)); | ||
489 | old_data_direction = scmd->sc_data_direction; | ||
490 | old_cmd_len = scmd->cmd_len; | ||
491 | old_use_sg = scmd->use_sg; | ||
492 | |||
493 | if (copy_sense) { | ||
494 | int gfp_mask = GFP_ATOMIC; | ||
495 | |||
496 | if (shost->hostt->unchecked_isa_dma) | ||
497 | gfp_mask |= __GFP_DMA; | ||
498 | |||
499 | scmd->sc_data_direction = DMA_FROM_DEVICE; | ||
500 | scmd->request_bufflen = 252; | ||
501 | scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask); | ||
502 | if (!scmd->request_buffer) | ||
503 | return FAILED; | ||
504 | } else { | ||
505 | scmd->request_buffer = NULL; | ||
506 | scmd->request_bufflen = 0; | ||
507 | scmd->sc_data_direction = DMA_NONE; | ||
508 | } | ||
509 | |||
510 | scmd->underflow = 0; | ||
511 | scmd->use_sg = 0; | ||
512 | scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); | ||
513 | |||
472 | if (sdev->scsi_level <= SCSI_2) | 514 | if (sdev->scsi_level <= SCSI_2) |
473 | scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | | 515 | scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | |
474 | (sdev->lun << 5 & 0xe0); | 516 | (sdev->lun << 5 & 0xe0); |
475 | 517 | ||
518 | /* | ||
519 | * Zero the sense buffer. The scsi spec mandates that any | ||
520 | * untransferred sense data should be interpreted as being zero. | ||
521 | */ | ||
522 | memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); | ||
523 | |||
476 | shost->eh_action = &done; | 524 | shost->eh_action = &done; |
477 | 525 | ||
478 | spin_lock_irqsave(shost->host_lock, flags); | 526 | spin_lock_irqsave(shost->host_lock, flags); |
@@ -522,6 +570,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) | |||
522 | rtn = FAILED; | 570 | rtn = FAILED; |
523 | } | 571 | } |
524 | 572 | ||
573 | |||
574 | /* | ||
575 | * Last chance to have valid sense data. | ||
576 | */ | ||
577 | if (copy_sense) { | ||
578 | if (!SCSI_SENSE_VALID(scmd)) { | ||
579 | memcpy(scmd->sense_buffer, scmd->request_buffer, | ||
580 | sizeof(scmd->sense_buffer)); | ||
581 | } | ||
582 | kfree(scmd->request_buffer); | ||
583 | } | ||
584 | |||
585 | |||
586 | /* | ||
587 | * Restore original data | ||
588 | */ | ||
589 | scmd->request_buffer = old_buffer; | ||
590 | scmd->request_bufflen = old_bufflen; | ||
591 | memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd)); | ||
592 | scmd->sc_data_direction = old_data_direction; | ||
593 | scmd->cmd_len = old_cmd_len; | ||
594 | scmd->use_sg = old_use_sg; | ||
595 | scmd->result = old_result; | ||
525 | return rtn; | 596 | return rtn; |
526 | } | 597 | } |
527 | 598 | ||
@@ -537,56 +608,10 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) | |||
537 | static int scsi_request_sense(struct scsi_cmnd *scmd) | 608 | static int scsi_request_sense(struct scsi_cmnd *scmd) |
538 | { | 609 | { |
539 | static unsigned char generic_sense[6] = | 610 | static unsigned char generic_sense[6] = |
540 | {REQUEST_SENSE, 0, 0, 0, 252, 0}; | 611 | {REQUEST_SENSE, 0, 0, 0, 252, 0}; |
541 | unsigned char *scsi_result; | ||
542 | int saved_result; | ||
543 | int rtn; | ||
544 | 612 | ||
545 | memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense)); | 613 | memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense)); |
546 | 614 | return scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 1); | |
547 | scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0)); | ||
548 | |||
549 | |||
550 | if (unlikely(!scsi_result)) { | ||
551 | printk(KERN_ERR "%s: cannot allocate scsi_result.\n", | ||
552 | __FUNCTION__); | ||
553 | return FAILED; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * zero the sense buffer. some host adapters automatically always | ||
558 | * request sense, so it is not a good idea that | ||
559 | * scmd->request_buffer and scmd->sense_buffer point to the same | ||
560 | * address (db). 0 is not a valid sense code. | ||
561 | */ | ||
562 | memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); | ||
563 | memset(scsi_result, 0, 252); | ||
564 | |||
565 | saved_result = scmd->result; | ||
566 | scmd->request_buffer = scsi_result; | ||
567 | scmd->request_bufflen = 252; | ||
568 | scmd->use_sg = 0; | ||
569 | scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); | ||
570 | scmd->sc_data_direction = DMA_FROM_DEVICE; | ||
571 | scmd->underflow = 0; | ||
572 | |||
573 | rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT); | ||
574 | |||
575 | /* last chance to have valid sense data */ | ||
576 | if(!SCSI_SENSE_VALID(scmd)) { | ||
577 | memcpy(scmd->sense_buffer, scmd->request_buffer, | ||
578 | sizeof(scmd->sense_buffer)); | ||
579 | } | ||
580 | |||
581 | kfree(scsi_result); | ||
582 | |||
583 | /* | ||
584 | * when we eventually call scsi_finish, we really wish to complete | ||
585 | * the original request, so let's restore the original data. (db) | ||
586 | */ | ||
587 | scsi_setup_cmd_retry(scmd); | ||
588 | scmd->result = saved_result; | ||
589 | return rtn; | ||
590 | } | 615 | } |
591 | 616 | ||
592 | /** | 617 | /** |
@@ -605,12 +630,6 @@ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) | |||
605 | { | 630 | { |
606 | scmd->device->host->host_failed--; | 631 | scmd->device->host->host_failed--; |
607 | scmd->eh_eflags = 0; | 632 | scmd->eh_eflags = 0; |
608 | |||
609 | /* | ||
610 | * set this back so that the upper level can correctly free up | ||
611 | * things. | ||
612 | */ | ||
613 | scsi_setup_cmd_retry(scmd); | ||
614 | list_move_tail(&scmd->eh_entry, done_q); | 633 | list_move_tail(&scmd->eh_entry, done_q); |
615 | } | 634 | } |
616 | EXPORT_SYMBOL(scsi_eh_finish_cmd); | 635 | EXPORT_SYMBOL(scsi_eh_finish_cmd); |
@@ -715,47 +734,26 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd) | |||
715 | { | 734 | { |
716 | static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; | 735 | static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; |
717 | int retry_cnt = 1, rtn; | 736 | int retry_cnt = 1, rtn; |
718 | int saved_result; | ||
719 | 737 | ||
720 | retry_tur: | 738 | retry_tur: |
721 | memcpy(scmd->cmnd, tur_command, sizeof(tur_command)); | 739 | memcpy(scmd->cmnd, tur_command, sizeof(tur_command)); |
722 | 740 | ||
723 | /* | ||
724 | * zero the sense buffer. the scsi spec mandates that any | ||
725 | * untransferred sense data should be interpreted as being zero. | ||
726 | */ | ||
727 | memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); | ||
728 | |||
729 | saved_result = scmd->result; | ||
730 | scmd->request_buffer = NULL; | ||
731 | scmd->request_bufflen = 0; | ||
732 | scmd->use_sg = 0; | ||
733 | scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); | ||
734 | scmd->underflow = 0; | ||
735 | scmd->sc_data_direction = DMA_NONE; | ||
736 | 741 | ||
737 | rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT); | 742 | rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 0); |
738 | 743 | ||
739 | /* | ||
740 | * when we eventually call scsi_finish, we really wish to complete | ||
741 | * the original request, so let's restore the original data. (db) | ||
742 | */ | ||
743 | scsi_setup_cmd_retry(scmd); | ||
744 | scmd->result = saved_result; | ||
745 | |||
746 | /* | ||
747 | * hey, we are done. let's look to see what happened. | ||
748 | */ | ||
749 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", | 744 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", |
750 | __FUNCTION__, scmd, rtn)); | 745 | __FUNCTION__, scmd, rtn)); |
751 | if (rtn == SUCCESS) | 746 | |
752 | return 0; | 747 | switch (rtn) { |
753 | else if (rtn == NEEDS_RETRY) { | 748 | case NEEDS_RETRY: |
754 | if (retry_cnt--) | 749 | if (retry_cnt--) |
755 | goto retry_tur; | 750 | goto retry_tur; |
751 | /*FALLTHRU*/ | ||
752 | case SUCCESS: | ||
756 | return 0; | 753 | return 0; |
754 | default: | ||
755 | return 1; | ||
757 | } | 756 | } |
758 | return 1; | ||
759 | } | 757 | } |
760 | 758 | ||
761 | /** | 759 | /** |
@@ -837,44 +835,16 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) | |||
837 | static int scsi_eh_try_stu(struct scsi_cmnd *scmd) | 835 | static int scsi_eh_try_stu(struct scsi_cmnd *scmd) |
838 | { | 836 | { |
839 | static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; | 837 | static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; |
840 | int rtn; | ||
841 | int saved_result; | ||
842 | 838 | ||
843 | if (!scmd->device->allow_restart) | 839 | if (scmd->device->allow_restart) { |
844 | return 1; | 840 | int rtn; |
845 | |||
846 | memcpy(scmd->cmnd, stu_command, sizeof(stu_command)); | ||
847 | |||
848 | /* | ||
849 | * zero the sense buffer. the scsi spec mandates that any | ||
850 | * untransferred sense data should be interpreted as being zero. | ||
851 | */ | ||
852 | memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); | ||
853 | |||
854 | saved_result = scmd->result; | ||
855 | scmd->request_buffer = NULL; | ||
856 | scmd->request_bufflen = 0; | ||
857 | scmd->use_sg = 0; | ||
858 | scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); | ||
859 | scmd->underflow = 0; | ||
860 | scmd->sc_data_direction = DMA_NONE; | ||
861 | 841 | ||
862 | rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT); | 842 | memcpy(scmd->cmnd, stu_command, sizeof(stu_command)); |
863 | 843 | rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT, 0); | |
864 | /* | 844 | if (rtn == SUCCESS) |
865 | * when we eventually call scsi_finish, we really wish to complete | 845 | return 0; |
866 | * the original request, so let's restore the original data. (db) | 846 | } |
867 | */ | ||
868 | scsi_setup_cmd_retry(scmd); | ||
869 | scmd->result = saved_result; | ||
870 | 847 | ||
871 | /* | ||
872 | * hey, we are done. let's look to see what happened. | ||
873 | */ | ||
874 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", | ||
875 | __FUNCTION__, scmd, rtn)); | ||
876 | if (rtn == SUCCESS) | ||
877 | return 0; | ||
878 | return 1; | 848 | return 1; |
879 | } | 849 | } |
880 | 850 | ||
@@ -1684,8 +1654,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) | |||
1684 | 1654 | ||
1685 | scmd->scsi_done = scsi_reset_provider_done_command; | 1655 | scmd->scsi_done = scsi_reset_provider_done_command; |
1686 | scmd->done = NULL; | 1656 | scmd->done = NULL; |
1687 | scmd->buffer = NULL; | ||
1688 | scmd->bufflen = 0; | ||
1689 | scmd->request_buffer = NULL; | 1657 | scmd->request_buffer = NULL; |
1690 | scmd->request_bufflen = 0; | 1658 | scmd->request_bufflen = 0; |
1691 | 1659 | ||