diff options
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r-- | drivers/scsi/scsi_error.c | 218 |
1 files changed, 93 insertions, 125 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6683d596234a..a8ed5a22009d 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -460,19 +460,71 @@ 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, unsigned char *cmnd, |
464 | int cmnd_size, int timeout, int copy_sense) | ||
464 | { | 465 | { |
465 | struct scsi_device *sdev = scmd->device; | 466 | struct scsi_device *sdev = scmd->device; |
466 | struct Scsi_Host *shost = sdev->host; | 467 | struct Scsi_Host *shost = sdev->host; |
468 | int old_result = scmd->result; | ||
467 | DECLARE_COMPLETION(done); | 469 | DECLARE_COMPLETION(done); |
468 | unsigned long timeleft; | 470 | unsigned long timeleft; |
469 | unsigned long flags; | 471 | unsigned long flags; |
472 | unsigned char old_cmnd[MAX_COMMAND_SIZE]; | ||
473 | enum dma_data_direction old_data_direction; | ||
474 | unsigned short old_use_sg; | ||
475 | unsigned char old_cmd_len; | ||
476 | unsigned old_bufflen; | ||
477 | void *old_buffer; | ||
470 | int rtn; | 478 | int rtn; |
471 | 479 | ||
480 | /* | ||
481 | * We need saved copies of a number of fields - this is because | ||
482 | * error handling may need to overwrite these with different values | ||
483 | * to run different commands, and once error handling is complete, | ||
484 | * we will need to restore these values prior to running the actual | ||
485 | * command. | ||
486 | */ | ||
487 | old_buffer = scmd->request_buffer; | ||
488 | old_bufflen = scmd->request_bufflen; | ||
489 | memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd)); | ||
490 | old_data_direction = scmd->sc_data_direction; | ||
491 | old_cmd_len = scmd->cmd_len; | ||
492 | old_use_sg = scmd->use_sg; | ||
493 | |||
494 | memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); | ||
495 | memcpy(scmd->cmnd, cmnd, cmnd_size); | ||
496 | |||
497 | if (copy_sense) { | ||
498 | int gfp_mask = GFP_ATOMIC; | ||
499 | |||
500 | if (shost->hostt->unchecked_isa_dma) | ||
501 | gfp_mask |= __GFP_DMA; | ||
502 | |||
503 | scmd->sc_data_direction = DMA_FROM_DEVICE; | ||
504 | scmd->request_bufflen = 252; | ||
505 | scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask); | ||
506 | if (!scmd->request_buffer) | ||
507 | return FAILED; | ||
508 | } else { | ||
509 | scmd->request_buffer = NULL; | ||
510 | scmd->request_bufflen = 0; | ||
511 | scmd->sc_data_direction = DMA_NONE; | ||
512 | } | ||
513 | |||
514 | scmd->underflow = 0; | ||
515 | scmd->use_sg = 0; | ||
516 | scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); | ||
517 | |||
472 | if (sdev->scsi_level <= SCSI_2) | 518 | if (sdev->scsi_level <= SCSI_2) |
473 | scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | | 519 | scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | |
474 | (sdev->lun << 5 & 0xe0); | 520 | (sdev->lun << 5 & 0xe0); |
475 | 521 | ||
522 | /* | ||
523 | * Zero the sense buffer. The scsi spec mandates that any | ||
524 | * untransferred sense data should be interpreted as being zero. | ||
525 | */ | ||
526 | memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); | ||
527 | |||
476 | shost->eh_action = &done; | 528 | shost->eh_action = &done; |
477 | 529 | ||
478 | spin_lock_irqsave(shost->host_lock, flags); | 530 | spin_lock_irqsave(shost->host_lock, flags); |
@@ -522,6 +574,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) | |||
522 | rtn = FAILED; | 574 | rtn = FAILED; |
523 | } | 575 | } |
524 | 576 | ||
577 | |||
578 | /* | ||
579 | * Last chance to have valid sense data. | ||
580 | */ | ||
581 | if (copy_sense) { | ||
582 | if (!SCSI_SENSE_VALID(scmd)) { | ||
583 | memcpy(scmd->sense_buffer, scmd->request_buffer, | ||
584 | sizeof(scmd->sense_buffer)); | ||
585 | } | ||
586 | kfree(scmd->request_buffer); | ||
587 | } | ||
588 | |||
589 | |||
590 | /* | ||
591 | * Restore original data | ||
592 | */ | ||
593 | scmd->request_buffer = old_buffer; | ||
594 | scmd->request_bufflen = old_bufflen; | ||
595 | memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd)); | ||
596 | scmd->sc_data_direction = old_data_direction; | ||
597 | scmd->cmd_len = old_cmd_len; | ||
598 | scmd->use_sg = old_use_sg; | ||
599 | scmd->result = old_result; | ||
525 | return rtn; | 600 | return rtn; |
526 | } | 601 | } |
527 | 602 | ||
@@ -537,56 +612,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) | |||
537 | static int scsi_request_sense(struct scsi_cmnd *scmd) | 612 | static int scsi_request_sense(struct scsi_cmnd *scmd) |
538 | { | 613 | { |
539 | static unsigned char generic_sense[6] = | 614 | static unsigned char generic_sense[6] = |
540 | {REQUEST_SENSE, 0, 0, 0, 252, 0}; | 615 | {REQUEST_SENSE, 0, 0, 0, 252, 0}; |
541 | unsigned char *scsi_result; | ||
542 | int saved_result; | ||
543 | int rtn; | ||
544 | |||
545 | memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense)); | ||
546 | |||
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 | 616 | ||
565 | saved_result = scmd->result; | 617 | return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1); |
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 | } | 618 | } |
591 | 619 | ||
592 | /** | 620 | /** |
@@ -605,12 +633,6 @@ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) | |||
605 | { | 633 | { |
606 | scmd->device->host->host_failed--; | 634 | scmd->device->host->host_failed--; |
607 | scmd->eh_eflags = 0; | 635 | 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); | 636 | list_move_tail(&scmd->eh_entry, done_q); |
615 | } | 637 | } |
616 | EXPORT_SYMBOL(scsi_eh_finish_cmd); | 638 | EXPORT_SYMBOL(scsi_eh_finish_cmd); |
@@ -715,47 +737,23 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd) | |||
715 | { | 737 | { |
716 | static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; | 738 | static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; |
717 | int retry_cnt = 1, rtn; | 739 | int retry_cnt = 1, rtn; |
718 | int saved_result; | ||
719 | 740 | ||
720 | retry_tur: | 741 | retry_tur: |
721 | memcpy(scmd->cmnd, tur_command, sizeof(tur_command)); | 742 | rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); |
722 | |||
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 | 743 | ||
737 | rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT); | ||
738 | |||
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 | |||
843 | if (!scmd->device->allow_restart) | ||
844 | return 1; | ||
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 | 838 | ||
854 | saved_result = scmd->result; | 839 | if (scmd->device->allow_restart) { |
855 | scmd->request_buffer = NULL; | 840 | int rtn; |
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 | rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, |
863 | 843 | 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 | ||