diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2007-10-08 10:36:45 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:54:58 -0400 |
commit | e1c234685c50807e10a3e7873e6e006976a4d8e8 (patch) | |
tree | 4be0f09620503f6669a40dacd49326443c9c07dc | |
parent | 55db6c1b8ed52bfc876e87971de8c67c42f36909 (diff) |
[SCSI] scsi_error: Refactoring scsi_error to facilitate in synchronous REQUEST_SENSE
- Drivers/transports that want to send a synchronous REQUEST_SENSE command
as part of their .queuecommand sequence, have 2 new API's that facilitate
in doing so and abstract them from scsi-ml internals.
void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
struct scsi_eh_save *sesci, unsigned char *cmnd,
int cmnd_size, int sense_bytes)
Will hijack a command and prepare it for request sense if needed.
And will save any later needed info into a scsi_eh_save structure.
void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
struct scsi_eh_save *sesci);
Will undo any changes done to a command by above function. Making
it ready for completion.
- Re-factor scsi_send_eh_cmnd() to use above APIs
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/scsi_error.c | 114 | ||||
-rw-r--r-- | include/scsi/scsi_eh.h | 23 |
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 | **/ |
609 | static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, | 606 | void 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 | } | ||
663 | EXPORT_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 | **/ | ||
672 | void 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 | } | ||
686 | EXPORT_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 | **/ | ||
702 | static 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 | ||
4 | struct scsi_cmnd; | 4 | #include <scsi/scsi_cmnd.h> |
5 | struct scsi_device; | 5 | struct scsi_device; |
6 | struct Scsi_Host; | 6 | struct Scsi_Host; |
7 | 7 | ||
@@ -65,4 +65,25 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, | |||
65 | 65 | ||
66 | extern int scsi_reset_provider(struct scsi_device *, int); | 66 | extern int scsi_reset_provider(struct scsi_device *, int); |
67 | 67 | ||
68 | struct 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 | |||
82 | extern 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 | |||
86 | extern 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 */ |