diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2007-12-13 06:50:53 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-30 14:03:41 -0500 |
commit | 6f9a35e2dafa0f855ab051c11bdbf739745ff6f5 (patch) | |
tree | 5ca273c98b61a4d329653ef30faa2c0414eccd2b | |
parent | 30b0c37b27485a9cb897bfe3824f6f517b8c80d6 (diff) |
[SCSI] bidirectional command support
At the block level bidi request uses req->next_rq pointer for a second
bidi_read request.
At Scsi-midlayer a second scsi_data_buffer structure is used for the
bidi_read part. This bidi scsi_data_buffer is put on
request->next_rq->special. Struct scsi_cmnd is not changed.
- Define scsi_bidi_cmnd() to return true if it is a bidi request and a
second sgtable was allocated.
- Define scsi_in()/scsi_out() to return the in or out scsi_data_buffer
from this command This API is to isolate users from the mechanics of
bidi.
- Define scsi_end_bidi_request() to do what scsi_end_request() does but
for a bidi request. This is necessary because bidi commands are a bit
tricky here. (See comments in body)
- scsi_release_buffers() will also release the bidi_read scsi_data_buffer
- scsi_io_completion() on bidi commands will now call
scsi_end_bidi_request() and return.
- The previous work done in scsi_init_io() is now done in a new
scsi_init_sgtable() (which is 99% identical to old scsi_init_io())
The new scsi_init_io() will call the above twice if needed also for
the bidi_read command. Only at this point is a command bidi.
- In scsi_error.c at scsi_eh_prep/restore_cmnd() make sure bidi-lld is not
confused by a get-sense command that looks like bidi. This is done
by puting NULL at request->next_rq, and restoring.
[jejb: update to sg_table and resolve conflicts
also update to blk-end-request and resolve conflicts]
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/scsi_error.c | 3 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 106 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 19 | ||||
-rw-r--r-- | include/scsi/scsi_eh.h | 1 |
4 files changed, 113 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4f4edc388c07..045a0868fc7b 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -618,9 +618,11 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, | |||
618 | memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd)); | 618 | memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd)); |
619 | ses->data_direction = scmd->sc_data_direction; | 619 | ses->data_direction = scmd->sc_data_direction; |
620 | ses->sdb = scmd->sdb; | 620 | ses->sdb = scmd->sdb; |
621 | ses->next_rq = scmd->request->next_rq; | ||
621 | ses->result = scmd->result; | 622 | ses->result = scmd->result; |
622 | 623 | ||
623 | memset(&scmd->sdb, 0, sizeof(scmd->sdb)); | 624 | memset(&scmd->sdb, 0, sizeof(scmd->sdb)); |
625 | scmd->request->next_rq = NULL; | ||
624 | 626 | ||
625 | if (sense_bytes) { | 627 | if (sense_bytes) { |
626 | scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE, | 628 | scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE, |
@@ -673,6 +675,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) | |||
673 | memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd)); | 675 | memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd)); |
674 | scmd->sc_data_direction = ses->data_direction; | 676 | scmd->sc_data_direction = ses->data_direction; |
675 | scmd->sdb = ses->sdb; | 677 | scmd->sdb = ses->sdb; |
678 | scmd->request->next_rq = ses->next_rq; | ||
676 | scmd->result = ses->result; | 679 | scmd->result = ses->result; |
677 | } | 680 | } |
678 | EXPORT_SYMBOL(scsi_eh_restore_cmnd); | 681 | EXPORT_SYMBOL(scsi_eh_restore_cmnd); |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d5e77e9b3a9c..681ed1b830f5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -64,6 +64,8 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { | |||
64 | }; | 64 | }; |
65 | #undef SP | 65 | #undef SP |
66 | 66 | ||
67 | static struct kmem_cache *scsi_bidi_sdb_cache; | ||
68 | |||
67 | static void scsi_run_queue(struct request_queue *q); | 69 | static void scsi_run_queue(struct request_queue *q); |
68 | 70 | ||
69 | /* | 71 | /* |
@@ -790,10 +792,38 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) | |||
790 | scsi_free_sgtable(&cmd->sdb); | 792 | scsi_free_sgtable(&cmd->sdb); |
791 | 793 | ||
792 | memset(&cmd->sdb, 0, sizeof(cmd->sdb)); | 794 | memset(&cmd->sdb, 0, sizeof(cmd->sdb)); |
795 | |||
796 | if (scsi_bidi_cmnd(cmd)) { | ||
797 | struct scsi_data_buffer *bidi_sdb = | ||
798 | cmd->request->next_rq->special; | ||
799 | scsi_free_sgtable(bidi_sdb); | ||
800 | kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb); | ||
801 | cmd->request->next_rq->special = NULL; | ||
802 | } | ||
793 | } | 803 | } |
794 | EXPORT_SYMBOL(scsi_release_buffers); | 804 | EXPORT_SYMBOL(scsi_release_buffers); |
795 | 805 | ||
796 | /* | 806 | /* |
807 | * Bidi commands Must be complete as a whole, both sides at once. | ||
808 | * If part of the bytes were written and lld returned | ||
809 | * scsi_in()->resid and/or scsi_out()->resid this information will be left | ||
810 | * in req->data_len and req->next_rq->data_len. The upper-layer driver can | ||
811 | * decide what to do with this information. | ||
812 | */ | ||
813 | void scsi_end_bidi_request(struct scsi_cmnd *cmd) | ||
814 | { | ||
815 | blk_end_bidi_request(cmd->request, 0, scsi_out(cmd)->resid, | ||
816 | scsi_in(cmd)->resid); | ||
817 | scsi_release_buffers(cmd); | ||
818 | |||
819 | /* | ||
820 | * This will goose the queue request function at the end, so we don't | ||
821 | * need to worry about launching another command. | ||
822 | */ | ||
823 | scsi_next_command(cmd); | ||
824 | } | ||
825 | |||
826 | /* | ||
797 | * Function: scsi_io_completion() | 827 | * Function: scsi_io_completion() |
798 | * | 828 | * |
799 | * Purpose: Completion processing for block device I/O requests. | 829 | * Purpose: Completion processing for block device I/O requests. |
@@ -854,9 +884,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) | |||
854 | req->sense_len = len; | 884 | req->sense_len = len; |
855 | } | 885 | } |
856 | } | 886 | } |
887 | if (scsi_bidi_cmnd(cmd)) { | ||
888 | /* will also release_buffers */ | ||
889 | scsi_end_bidi_request(cmd); | ||
890 | return; | ||
891 | } | ||
857 | req->data_len = scsi_get_resid(cmd); | 892 | req->data_len = scsi_get_resid(cmd); |
858 | } | 893 | } |
859 | 894 | ||
895 | BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ | ||
860 | scsi_release_buffers(cmd); | 896 | scsi_release_buffers(cmd); |
861 | 897 | ||
862 | /* | 898 | /* |
@@ -982,28 +1018,16 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) | |||
982 | scsi_end_request(cmd, -EIO, this_count, !result); | 1018 | scsi_end_request(cmd, -EIO, this_count, !result); |
983 | } | 1019 | } |
984 | 1020 | ||
985 | /* | 1021 | static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, |
986 | * Function: scsi_init_io() | 1022 | gfp_t gfp_mask) |
987 | * | ||
988 | * Purpose: SCSI I/O initialize function. | ||
989 | * | ||
990 | * Arguments: cmd - Command descriptor we wish to initialize | ||
991 | * | ||
992 | * Returns: 0 on success | ||
993 | * BLKPREP_DEFER if the failure is retryable | ||
994 | */ | ||
995 | int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | ||
996 | { | 1023 | { |
997 | struct request *req = cmd->request; | 1024 | int count; |
998 | int count; | ||
999 | struct scsi_data_buffer *sdb = &cmd->sdb; | ||
1000 | 1025 | ||
1001 | /* | 1026 | /* |
1002 | * If sg table allocation fails, requeue request later. | 1027 | * If sg table allocation fails, requeue request later. |
1003 | */ | 1028 | */ |
1004 | if (unlikely(scsi_alloc_sgtable(sdb, req->nr_phys_segments, | 1029 | if (unlikely(scsi_alloc_sgtable(sdb, req->nr_phys_segments, |
1005 | gfp_mask))) { | 1030 | gfp_mask))) { |
1006 | scsi_unprep_request(req); | ||
1007 | return BLKPREP_DEFER; | 1031 | return BLKPREP_DEFER; |
1008 | } | 1032 | } |
1009 | 1033 | ||
@@ -1022,6 +1046,50 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | |||
1022 | sdb->table.nents = count; | 1046 | sdb->table.nents = count; |
1023 | return BLKPREP_OK; | 1047 | return BLKPREP_OK; |
1024 | } | 1048 | } |
1049 | |||
1050 | /* | ||
1051 | * Function: scsi_init_io() | ||
1052 | * | ||
1053 | * Purpose: SCSI I/O initialize function. | ||
1054 | * | ||
1055 | * Arguments: cmd - Command descriptor we wish to initialize | ||
1056 | * | ||
1057 | * Returns: 0 on success | ||
1058 | * BLKPREP_DEFER if the failure is retryable | ||
1059 | * BLKPREP_KILL if the failure is fatal | ||
1060 | */ | ||
1061 | int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | ||
1062 | { | ||
1063 | int error = scsi_init_sgtable(cmd->request, &cmd->sdb, gfp_mask); | ||
1064 | if (error) | ||
1065 | goto err_exit; | ||
1066 | |||
1067 | if (blk_bidi_rq(cmd->request)) { | ||
1068 | struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( | ||
1069 | scsi_bidi_sdb_cache, GFP_ATOMIC); | ||
1070 | if (!bidi_sdb) { | ||
1071 | error = BLKPREP_DEFER; | ||
1072 | goto err_exit; | ||
1073 | } | ||
1074 | |||
1075 | cmd->request->next_rq->special = bidi_sdb; | ||
1076 | error = scsi_init_sgtable(cmd->request->next_rq, bidi_sdb, | ||
1077 | GFP_ATOMIC); | ||
1078 | if (error) | ||
1079 | goto err_exit; | ||
1080 | } | ||
1081 | |||
1082 | return BLKPREP_OK ; | ||
1083 | |||
1084 | err_exit: | ||
1085 | scsi_release_buffers(cmd); | ||
1086 | if (error == BLKPREP_KILL) | ||
1087 | scsi_put_command(cmd); | ||
1088 | else /* BLKPREP_DEFER */ | ||
1089 | scsi_unprep_request(cmd->request); | ||
1090 | |||
1091 | return error; | ||
1092 | } | ||
1025 | EXPORT_SYMBOL(scsi_init_io); | 1093 | EXPORT_SYMBOL(scsi_init_io); |
1026 | 1094 | ||
1027 | static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, | 1095 | static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, |
@@ -1639,6 +1707,14 @@ int __init scsi_init_queue(void) | |||
1639 | return -ENOMEM; | 1707 | return -ENOMEM; |
1640 | } | 1708 | } |
1641 | 1709 | ||
1710 | scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb", | ||
1711 | sizeof(struct scsi_data_buffer), | ||
1712 | 0, 0, NULL); | ||
1713 | if (!scsi_bidi_sdb_cache) { | ||
1714 | printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n"); | ||
1715 | return -ENOMEM; | ||
1716 | } | ||
1717 | |||
1642 | for (i = 0; i < SG_MEMPOOL_NR; i++) { | 1718 | for (i = 0; i < SG_MEMPOOL_NR; i++) { |
1643 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; | 1719 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; |
1644 | int size = sgp->size * sizeof(struct scatterlist); | 1720 | int size = sgp->size * sizeof(struct scatterlist); |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index c6478bb6f963..de28aab820b0 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -2,12 +2,12 @@ | |||
2 | #define _SCSI_SCSI_CMND_H | 2 | #define _SCSI_SCSI_CMND_H |
3 | 3 | ||
4 | #include <linux/dma-mapping.h> | 4 | #include <linux/dma-mapping.h> |
5 | #include <linux/blkdev.h> | ||
5 | #include <linux/list.h> | 6 | #include <linux/list.h> |
6 | #include <linux/types.h> | 7 | #include <linux/types.h> |
7 | #include <linux/timer.h> | 8 | #include <linux/timer.h> |
8 | #include <linux/scatterlist.h> | 9 | #include <linux/scatterlist.h> |
9 | 10 | ||
10 | struct request; | ||
11 | struct Scsi_Host; | 11 | struct Scsi_Host; |
12 | struct scsi_device; | 12 | struct scsi_device; |
13 | 13 | ||
@@ -158,4 +158,21 @@ static inline int scsi_get_resid(struct scsi_cmnd *cmd) | |||
158 | #define scsi_for_each_sg(cmd, sg, nseg, __i) \ | 158 | #define scsi_for_each_sg(cmd, sg, nseg, __i) \ |
159 | for_each_sg(scsi_sglist(cmd), sg, nseg, __i) | 159 | for_each_sg(scsi_sglist(cmd), sg, nseg, __i) |
160 | 160 | ||
161 | static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd) | ||
162 | { | ||
163 | return blk_bidi_rq(cmd->request) && | ||
164 | (cmd->request->next_rq->special != NULL); | ||
165 | } | ||
166 | |||
167 | static inline struct scsi_data_buffer *scsi_in(struct scsi_cmnd *cmd) | ||
168 | { | ||
169 | return scsi_bidi_cmnd(cmd) ? | ||
170 | cmd->request->next_rq->special : &cmd->sdb; | ||
171 | } | ||
172 | |||
173 | static inline struct scsi_data_buffer *scsi_out(struct scsi_cmnd *cmd) | ||
174 | { | ||
175 | return &cmd->sdb; | ||
176 | } | ||
177 | |||
161 | #endif /* _SCSI_SCSI_CMND_H */ | 178 | #endif /* _SCSI_SCSI_CMND_H */ |
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 1e08be1466ee..25071d5d9bf8 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h | |||
@@ -74,6 +74,7 @@ struct scsi_eh_save { | |||
74 | unsigned char cmd_len; | 74 | unsigned char cmd_len; |
75 | unsigned char cmnd[MAX_COMMAND_SIZE]; | 75 | unsigned char cmnd[MAX_COMMAND_SIZE]; |
76 | struct scsi_data_buffer sdb; | 76 | struct scsi_data_buffer sdb; |
77 | struct request *next_rq; | ||
77 | 78 | ||
78 | /* new command support */ | 79 | /* new command support */ |
79 | struct scatterlist sense_sgl; | 80 | struct scatterlist sense_sgl; |