aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2007-12-13 06:50:53 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-30 14:03:41 -0500
commit6f9a35e2dafa0f855ab051c11bdbf739745ff6f5 (patch)
tree5ca273c98b61a4d329653ef30faa2c0414eccd2b
parent30b0c37b27485a9cb897bfe3824f6f517b8c80d6 (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.c3
-rw-r--r--drivers/scsi/scsi_lib.c106
-rw-r--r--include/scsi/scsi_cmnd.h19
-rw-r--r--include/scsi/scsi_eh.h1
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}
678EXPORT_SYMBOL(scsi_eh_restore_cmnd); 681EXPORT_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
67static struct kmem_cache *scsi_bidi_sdb_cache;
68
67static void scsi_run_queue(struct request_queue *q); 69static 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}
794EXPORT_SYMBOL(scsi_release_buffers); 804EXPORT_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 */
813void 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/* 1021static 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 */
995int 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 */
1061int 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
1084err_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}
1025EXPORT_SYMBOL(scsi_init_io); 1093EXPORT_SYMBOL(scsi_init_io);
1026 1094
1027static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, 1095static 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
10struct request;
11struct Scsi_Host; 11struct Scsi_Host;
12struct scsi_device; 12struct 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
161static 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
167static 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
173static 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;