diff options
-rw-r--r-- | drivers/scsi/storvsc_drv.c | 101 |
1 files changed, 59 insertions, 42 deletions
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 82873e775fc3..95c759fe071a 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c | |||
@@ -761,6 +761,55 @@ cleanup: | |||
761 | return ret; | 761 | return ret; |
762 | } | 762 | } |
763 | 763 | ||
764 | static void storvsc_handle_error(struct vmscsi_request *vm_srb, | ||
765 | struct scsi_cmnd *scmnd, | ||
766 | struct Scsi_Host *host, | ||
767 | u8 asc, u8 ascq) | ||
768 | { | ||
769 | struct storvsc_scan_work *wrk; | ||
770 | void (*process_err_fn)(struct work_struct *work); | ||
771 | bool do_work = false; | ||
772 | |||
773 | switch (vm_srb->srb_status) { | ||
774 | case SRB_STATUS_ERROR: | ||
775 | /* | ||
776 | * If there is an error; offline the device since all | ||
777 | * error recovery strategies would have already been | ||
778 | * deployed on the host side. However, if the command | ||
779 | * were a pass-through command deal with it appropriately. | ||
780 | */ | ||
781 | switch (scmnd->cmnd[0]) { | ||
782 | case ATA_16: | ||
783 | case ATA_12: | ||
784 | set_host_byte(scmnd, DID_PASSTHROUGH); | ||
785 | break; | ||
786 | default: | ||
787 | set_host_byte(scmnd, DID_TARGET_FAILURE); | ||
788 | } | ||
789 | break; | ||
790 | case SRB_STATUS_INVALID_LUN: | ||
791 | do_work = true; | ||
792 | process_err_fn = storvsc_remove_lun; | ||
793 | break; | ||
794 | } | ||
795 | if (!do_work) | ||
796 | return; | ||
797 | |||
798 | /* | ||
799 | * We need to schedule work to process this error; schedule it. | ||
800 | */ | ||
801 | wrk = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC); | ||
802 | if (!wrk) { | ||
803 | set_host_byte(scmnd, DID_TARGET_FAILURE); | ||
804 | return; | ||
805 | } | ||
806 | |||
807 | wrk->host = host; | ||
808 | wrk->lun = vm_srb->lun; | ||
809 | INIT_WORK(&wrk->work, process_err_fn); | ||
810 | schedule_work(&wrk->work); | ||
811 | } | ||
812 | |||
764 | 813 | ||
765 | static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) | 814 | static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) |
766 | { | 815 | { |
@@ -769,8 +818,13 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) | |||
769 | void (*scsi_done_fn)(struct scsi_cmnd *); | 818 | void (*scsi_done_fn)(struct scsi_cmnd *); |
770 | struct scsi_sense_hdr sense_hdr; | 819 | struct scsi_sense_hdr sense_hdr; |
771 | struct vmscsi_request *vm_srb; | 820 | struct vmscsi_request *vm_srb; |
772 | struct storvsc_scan_work *wrk; | ||
773 | struct stor_mem_pools *memp = scmnd->device->hostdata; | 821 | struct stor_mem_pools *memp = scmnd->device->hostdata; |
822 | struct Scsi_Host *host; | ||
823 | struct storvsc_device *stor_dev; | ||
824 | struct hv_device *dev = host_dev->dev; | ||
825 | |||
826 | stor_dev = get_in_stor_device(dev); | ||
827 | host = stor_dev->host; | ||
774 | 828 | ||
775 | vm_srb = &cmd_request->vstor_packet.vm_srb; | 829 | vm_srb = &cmd_request->vstor_packet.vm_srb; |
776 | if (cmd_request->bounce_sgl_count) { | 830 | if (cmd_request->bounce_sgl_count) { |
@@ -783,55 +837,18 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) | |||
783 | cmd_request->bounce_sgl_count); | 837 | cmd_request->bounce_sgl_count); |
784 | } | 838 | } |
785 | 839 | ||
786 | /* | ||
787 | * If there is an error; offline the device since all | ||
788 | * error recovery strategies would have already been | ||
789 | * deployed on the host side. However, if the command | ||
790 | * were a pass-through command deal with it appropriately. | ||
791 | */ | ||
792 | scmnd->result = vm_srb->scsi_status; | 840 | scmnd->result = vm_srb->scsi_status; |
793 | 841 | ||
794 | if (vm_srb->srb_status == SRB_STATUS_ERROR) { | ||
795 | switch (scmnd->cmnd[0]) { | ||
796 | case ATA_16: | ||
797 | case ATA_12: | ||
798 | set_host_byte(scmnd, DID_PASSTHROUGH); | ||
799 | break; | ||
800 | default: | ||
801 | set_host_byte(scmnd, DID_TARGET_FAILURE); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | |||
806 | /* | ||
807 | * If the LUN is invalid; remove the device. | ||
808 | */ | ||
809 | if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) { | ||
810 | struct storvsc_device *stor_dev; | ||
811 | struct hv_device *dev = host_dev->dev; | ||
812 | struct Scsi_Host *host; | ||
813 | |||
814 | stor_dev = get_in_stor_device(dev); | ||
815 | host = stor_dev->host; | ||
816 | |||
817 | wrk = kmalloc(sizeof(struct storvsc_scan_work), | ||
818 | GFP_ATOMIC); | ||
819 | if (!wrk) { | ||
820 | scmnd->result = DID_TARGET_FAILURE << 16; | ||
821 | } else { | ||
822 | wrk->host = host; | ||
823 | wrk->lun = vm_srb->lun; | ||
824 | INIT_WORK(&wrk->work, storvsc_remove_lun); | ||
825 | schedule_work(&wrk->work); | ||
826 | } | ||
827 | } | ||
828 | |||
829 | if (scmnd->result) { | 842 | if (scmnd->result) { |
830 | if (scsi_normalize_sense(scmnd->sense_buffer, | 843 | if (scsi_normalize_sense(scmnd->sense_buffer, |
831 | SCSI_SENSE_BUFFERSIZE, &sense_hdr)) | 844 | SCSI_SENSE_BUFFERSIZE, &sense_hdr)) |
832 | scsi_print_sense_hdr("storvsc", &sense_hdr); | 845 | scsi_print_sense_hdr("storvsc", &sense_hdr); |
833 | } | 846 | } |
834 | 847 | ||
848 | if (vm_srb->srb_status != SRB_STATUS_SUCCESS) | ||
849 | storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc, | ||
850 | sense_hdr.ascq); | ||
851 | |||
835 | scsi_set_resid(scmnd, | 852 | scsi_set_resid(scmnd, |
836 | cmd_request->data_buffer.len - | 853 | cmd_request->data_buffer.len - |
837 | vm_srb->data_transfer_length); | 854 | vm_srb->data_transfer_length); |