aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi_error.c114
-rw-r--r--include/scsi/scsi_eh.h23
2 files changed, 90 insertions, 47 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 4d535019e04b..d29f8464b74f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -590,42 +590,23 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
590} 590}
591 591
592/** 592/**
593 * scsi_send_eh_cmnd - submit a scsi command as part of error recory 593 * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory
594 * @scmd: SCSI command structure to hijack 594 * @scmd: SCSI command structure to hijack
595 * @ses: structure to save restore information
595 * @cmnd: CDB to send. Can be NULL if no new cmnd is needed 596 * @cmnd: CDB to send. Can be NULL if no new cmnd is needed
596 * @cmnd_size: size in bytes of @cmnd 597 * @cmnd_size: size in bytes of @cmnd
597 * @timeout: timeout for this request
598 * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored) 598 * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
599 * 599 *
600 * This function is used to send a scsi command down to a target device 600 * This function is used to save a scsi command information before re-execution
601 * as part of the error recovery process. If @sense_bytes is 0 the command 601 * as part of the error recovery process. If @sense_bytes is 0 the command
602 * sent must be one that does not transfer any data. If @sense_bytes != 0 602 * sent must be one that does not transfer any data. If @sense_bytes != 0
603 * @cmnd is ignored and this functions sets up a REQUEST_SENSE command 603 * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
604 * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer. 604 * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
605 *
606 * Return value:
607 * SUCCESS or FAILED or NEEDS_RETRY
608 **/ 605 **/
609static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, 606void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
610 int cmnd_size, int timeout, unsigned sense_bytes) 607 unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
611{ 608{
612 struct scsi_device *sdev = scmd->device; 609 struct scsi_device *sdev = scmd->device;
613 struct Scsi_Host *shost = sdev->host;
614 DECLARE_COMPLETION_ONSTACK(done);
615 unsigned long timeleft;
616 unsigned long flags;
617
618 unsigned char old_cmd_len;
619 unsigned char old_cmnd[MAX_COMMAND_SIZE];
620 enum dma_data_direction old_data_direction;
621 unsigned old_bufflen;
622 void *old_buffer;
623 unsigned short old_use_sg;
624 int old_resid;
625 int old_result;
626
627 struct scatterlist sgl;
628 int rtn;
629 610
630 /* 611 /*
631 * We need saved copies of a number of fields - this is because 612 * We need saved copies of a number of fields - this is because
@@ -634,20 +615,21 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
634 * we will need to restore these values prior to running the actual 615 * we will need to restore these values prior to running the actual
635 * command. 616 * command.
636 */ 617 */
637 old_cmd_len = scmd->cmd_len; 618 ses->cmd_len = scmd->cmd_len;
638 memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd)); 619 memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
639 old_data_direction = scmd->sc_data_direction; 620 ses->data_direction = scmd->sc_data_direction;
640 old_bufflen = scmd->request_bufflen; 621 ses->bufflen = scmd->request_bufflen;
641 old_buffer = scmd->request_buffer; 622 ses->buffer = scmd->request_buffer;
642 old_use_sg = scmd->use_sg; 623 ses->use_sg = scmd->use_sg;
643 old_resid = scmd->resid; 624 ses->resid = scmd->resid;
644 old_result = scmd->result; 625 ses->result = scmd->result;
645 626
646 if (sense_bytes) { 627 if (sense_bytes) {
647 scmd->request_bufflen = min_t(unsigned, 628 scmd->request_bufflen = min_t(unsigned,
648 sizeof(scmd->sense_buffer), sense_bytes); 629 sizeof(scmd->sense_buffer), sense_bytes);
649 sg_init_one(&sgl, scmd->sense_buffer, scmd->request_bufflen); 630 sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
650 scmd->request_buffer = &sgl; 631 scmd->request_bufflen);
632 scmd->request_buffer = &ses->sense_sgl;
651 scmd->sc_data_direction = DMA_FROM_DEVICE; 633 scmd->sc_data_direction = DMA_FROM_DEVICE;
652 scmd->use_sg = 1; 634 scmd->use_sg = 1;
653 memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); 635 memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
@@ -677,7 +659,58 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
677 * untransferred sense data should be interpreted as being zero. 659 * untransferred sense data should be interpreted as being zero.
678 */ 660 */
679 memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); 661 memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
662}
663EXPORT_SYMBOL(scsi_eh_prep_cmnd);
664
665/**
666 * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
667 * @scmd: SCSI command structure to restore
668 * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd
669 *
670 * Undo any damage done by above scsi_prep_eh_cmnd().
671 **/
672void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
673{
674 /*
675 * Restore original data
676 */
677 scmd->cmd_len = ses->cmd_len;
678 memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
679 scmd->sc_data_direction = ses->data_direction;
680 scmd->request_bufflen = ses->bufflen;
681 scmd->request_buffer = ses->buffer;
682 scmd->use_sg = ses->use_sg;
683 scmd->resid = ses->resid;
684 scmd->result = ses->result;
685}
686EXPORT_SYMBOL(scsi_eh_restore_cmnd);
680 687
688/**
689 * scsi_send_eh_cmnd - submit a scsi command as part of error recory
690 * @scmd: SCSI command structure to hijack
691 * @cmnd: CDB to send
692 * @cmnd_size: size in bytes of @cmnd
693 * @timeout: timeout for this request
694 * @sense_bytes: size of sense data to copy or 0
695 *
696 * This function is used to send a scsi command down to a target device
697 * as part of the error recovery process. See also scsi_eh_prep_cmnd() above.
698 *
699 * Return value:
700 * SUCCESS or FAILED or NEEDS_RETRY
701 **/
702static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
703 int cmnd_size, int timeout, unsigned sense_bytes)
704{
705 struct scsi_device *sdev = scmd->device;
706 struct Scsi_Host *shost = sdev->host;
707 DECLARE_COMPLETION_ONSTACK(done);
708 unsigned long timeleft;
709 unsigned long flags;
710 struct scsi_eh_save ses;
711 int rtn;
712
713 scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
681 shost->eh_action = &done; 714 shost->eh_action = &done;
682 715
683 spin_lock_irqsave(shost->host_lock, flags); 716 spin_lock_irqsave(shost->host_lock, flags);
@@ -721,18 +754,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
721 rtn = FAILED; 754 rtn = FAILED;
722 } 755 }
723 756
724 757 scsi_eh_restore_cmnd(scmd, &ses);
725 /*
726 * Restore original data
727 */
728 scmd->cmd_len = old_cmd_len;
729 memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
730 scmd->sc_data_direction = old_data_direction;
731 scmd->request_bufflen = old_bufflen;
732 scmd->request_buffer = old_buffer;
733 scmd->use_sg = old_use_sg;
734 scmd->resid = old_resid;
735 scmd->result = old_result;
736 return rtn; 758 return rtn;
737} 759}
738 760
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index c5c0f6762a01..44224ba4dd90 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -1,7 +1,7 @@
1#ifndef _SCSI_SCSI_EH_H 1#ifndef _SCSI_SCSI_EH_H
2#define _SCSI_SCSI_EH_H 2#define _SCSI_SCSI_EH_H
3 3
4struct scsi_cmnd; 4#include <scsi/scsi_cmnd.h>
5struct scsi_device; 5struct scsi_device;
6struct Scsi_Host; 6struct Scsi_Host;
7 7
@@ -65,4 +65,25 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
65 65
66extern int scsi_reset_provider(struct scsi_device *, int); 66extern int scsi_reset_provider(struct scsi_device *, int);
67 67
68struct scsi_eh_save {
69 int result;
70 enum dma_data_direction data_direction;
71 unsigned char cmd_len;
72 unsigned char cmnd[MAX_COMMAND_SIZE];
73
74 void *buffer;
75 unsigned bufflen;
76 unsigned short use_sg;
77 int resid;
78
79 struct scatterlist sense_sgl;
80};
81
82extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
83 struct scsi_eh_save *ses, unsigned char *cmnd,
84 int cmnd_size, unsigned sense_bytes);
85
86extern void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
87 struct scsi_eh_save *ses);
88
68#endif /* _SCSI_SCSI_EH_H */ 89#endif /* _SCSI_SCSI_EH_H */