From: Boaz Harrosh <bharrosh@panasas.com>
To: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>,
James Bottomley <James.Bottomley@SteelEye.com>,
linux-scsi <linux-scsi@vger.kernel.org>
Cc: Pete Wyckoff <pw@osc.edu>, Benny Halevy <bhalevy@panasas.com>,
Andrew Morton <akpm@osdl.org>
Subject: [PATCH 4/4] SCSI: bidi support
Date: Thu, 08 Nov 2007 19:03:18 +0200 [thread overview]
Message-ID: <47334156.8050105@panasas.com> (raw)
In-Reply-To: <47333E2A.7020307@panasas.com>
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.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
---
drivers/scsi/scsi_error.c | 3 +
drivers/scsi/scsi_lib.c | 154 ++++++++++++++++++++++++++++++++++++---------
include/scsi/scsi_cmnd.h | 23 +++++++-
include/scsi/scsi_eh.h | 1 +
4 files changed, 149 insertions(+), 32 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 9daa983..13b6802 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,
memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
ses->data_direction = scmd->sc_data_direction;
ses->sdb = scmd->sdb;
+ ses->next_rq = scmd->request->next_rq;
ses->result = scmd->result;
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
+ scmd->request->next_rq = NULL;
if (sense_bytes) {
scmd->sdb.length = min_t(unsigned,
@@ -673,6 +675,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
scmd->sc_data_direction = ses->data_direction;
scmd->sdb = ses->sdb;
+ scmd->request->next_rq = ses->next_rq;
scmd->result = ses->result;
}
EXPORT_SYMBOL(scsi_eh_restore_cmnd);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index edfd8d8..1ed6c6b 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[] = {
};
#undef SP
+static struct kmem_cache *scsi_bidi_sdb_cache;
+
static void scsi_run_queue(struct request_queue *q);
/*
@@ -625,6 +627,28 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
scsi_run_queue(sdev->request_queue);
}
+static void scsi_finalize_request(struct scsi_cmnd *cmd, int uptodate)
+{
+ struct request_queue *q = cmd->device->request_queue;
+ struct request *req = cmd->request;
+ unsigned long flags;
+
+ add_disk_randomness(req->rq_disk);
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ if (blk_rq_tagged(req))
+ blk_queue_end_tag(q, req);
+
+ end_that_request_last(req, uptodate);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ /*
+ * This will goose the queue request function at the end, so we don't
+ * need to worry about launching another command.
+ */
+ scsi_next_command(cmd);
+}
+
/*
* Function: scsi_end_request()
*
@@ -652,7 +676,6 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
{
struct request_queue *q = cmd->device->request_queue;
struct request *req = cmd->request;
- unsigned long flags;
/*
* If there are blocks left over at the end, set up the command
@@ -681,19 +704,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
}
}
- add_disk_randomness(req->rq_disk);
-
- spin_lock_irqsave(q->queue_lock, flags);
- if (blk_rq_tagged(req))
- blk_queue_end_tag(q, req);
- end_that_request_last(req, uptodate);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- /*
- * This will goose the queue request function at the end, so we don't
- * need to worry about launching another command.
- */
- scsi_next_command(cmd);
+ scsi_finalize_request(cmd, uptodate);
return NULL;
}
@@ -892,10 +903,47 @@ void scsi_release_buffers(struct scsi_cmnd *cmd)
scsi_free_sgtable(&cmd->sdb);
memset(&cmd->sdb, 0, sizeof(cmd->sdb));
+
+ if (scsi_bidi_cmnd(cmd)) {
+ struct scsi_data_buffer *bidi_sdb =
+ cmd->request->next_rq->special;
+ scsi_free_sgtable(bidi_sdb);
+ kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb);
+ cmd->request->next_rq->special = NULL;
+ }
}
EXPORT_SYMBOL(scsi_release_buffers);
/*
+ * Bidi commands Must be complete as a whole, both sides at once.
+ * If part of the bytes were written and lld returned
+ * scsi_in()->resid and/or scsi_out()->resid this information will be left
+ * in req->data_len and req->next_rq->data_len. The upper-layer driver can
+ * decide what to do with this information.
+ */
+void scsi_end_bidi_request(struct scsi_cmnd *cmd)
+{
+ struct request *req = cmd->request;
+
+ end_that_request_chunk(req, 1, req->data_len);
+ req->data_len = scsi_out(cmd)->resid;
+
+ end_that_request_chunk(req->next_rq, 1, req->next_rq->data_len);
+ req->next_rq->data_len = scsi_in(cmd)->resid;
+
+ scsi_release_buffers(cmd);
+
+ /*
+ *FIXME: If ll_rw_blk.c is changed to also put_request(req->next_rq)
+ * in end_that_request_last() then this WARN_ON must be removed.
+ * for now, upper-driver must have registered an end_io.
+ */
+ WARN_ON(!req->end_io);
+
+ scsi_finalize_request(cmd, 1);
+}
+
+/*
* Function: scsi_io_completion()
*
* Purpose: Completion processing for block device I/O requests.
@@ -956,9 +1004,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
req->sense_len = len;
}
}
+ if (scsi_bidi_cmnd(cmd)) {
+ /* will also release_buffers */
+ scsi_end_bidi_request(cmd);
+ return;
+ }
req->data_len = scsi_get_resid(cmd);
}
+ BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */
scsi_release_buffers(cmd);
/*
@@ -1084,25 +1138,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_end_request(cmd, 0, this_count, !result);
}
-/*
- * Function: scsi_init_io()
- *
- * Purpose: SCSI I/O initialize function.
- *
- * Arguments: cmd - Command descriptor we wish to initialize
- *
- * Returns: 0 on success
- * BLKPREP_DEFER if the failure is retryable
- * BLKPREP_KILL if the failure is fatal
- */
-int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
+ gfp_t gfp_mask)
{
- struct request *req = cmd->request;
- int count;
- struct scsi_data_buffer *sdb = &cmd->sdb;
+ int count;
if (scsi_alloc_sgtable(sdb, req->nr_phys_segments, gfp_mask)) {
- scsi_unprep_request(req);
return BLKPREP_DEFER;
}
@@ -1126,9 +1167,52 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
printk(KERN_ERR "counted %d, received %d\n", count, sdb->sg_count);
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
req->current_nr_sectors);
-
return BLKPREP_KILL;
}
+
+/*
+ * Function: scsi_init_io()
+ *
+ * Purpose: SCSI I/O initialize function.
+ *
+ * Arguments: cmd - Command descriptor we wish to initialize
+ *
+ * Returns: 0 on success
+ * BLKPREP_DEFER if the failure is retryable
+ * BLKPREP_KILL if the failure is fatal
+ */
+int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+ int error = scsi_init_sgtable(cmd->request, &cmd->sdb, gfp_mask);
+ if (error)
+ goto err_exit;
+
+ if (blk_bidi_rq(cmd->request)) {
+ struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc(
+ scsi_bidi_sdb_cache, GFP_ATOMIC);
+ if (!bidi_sdb) {
+ error = BLKPREP_DEFER;
+ goto err_exit;
+ }
+
+ cmd->request->next_rq->special = bidi_sdb;
+ error = scsi_init_sgtable(cmd->request->next_rq, bidi_sdb,
+ GFP_ATOMIC);
+ if (error)
+ goto err_exit;
+ }
+
+ return BLKPREP_OK ;
+
+err_exit:
+ scsi_release_buffers(cmd);
+ if (error == BLKPREP_KILL)
+ scsi_put_command(cmd);
+ else /* BLKPREP_DEFER */
+ scsi_unprep_request(cmd->request);
+
+ return error;
+}
EXPORT_SYMBOL(scsi_init_io);
static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
@@ -1738,6 +1822,14 @@ int __init scsi_init_queue(void)
return -ENOMEM;
}
+ scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb",
+ sizeof(struct scsi_data_buffer),
+ 0, 0, NULL);
+ if (!scsi_bidi_sdb_cache) {
+ printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n");
+ return -ENOMEM;
+ }
+
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
int size = sgp->size * sizeof(struct scatterlist);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 887a12a..cd2851a 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -2,12 +2,12 @@
#define _SCSI_SCSI_CMND_H
#include <linux/dma-mapping.h>
+#include <linux/blkdev.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/scatterlist.h>
-struct request;
struct scatterlist;
struct Scsi_Host;
struct scsi_device;
@@ -162,4 +162,25 @@ static inline int scsi_get_resid(struct scsi_cmnd *cmd)
#define scsi_for_each_sg(cmd, sg, nseg, __i) \
for_each_sg(scsi_sglist(cmd), sg, nseg, __i)
+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
+{
+ return blk_bidi_rq(cmd->request) &&
+ (cmd->request->next_rq->special != NULL);
+}
+
+static inline struct scsi_data_buffer *scsi_in(struct scsi_cmnd *cmd)
+{
+ WARN_ON((cmd->sc_data_direction != DMA_FROM_DEVICE) &&
+ !scsi_bidi_cmnd(cmd));
+ return scsi_bidi_cmnd(cmd) ?
+ cmd->request->next_rq->special : &cmd->sdb;
+}
+
+static inline struct scsi_data_buffer *scsi_out(struct scsi_cmnd *cmd)
+{
+ WARN_ON((cmd->sc_data_direction != DMA_TO_DEVICE) &&
+ !scsi_bidi_cmnd(cmd));
+ return &cmd->sdb;
+}
+
#endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 1e08be1..25071d5 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -74,6 +74,7 @@ struct scsi_eh_save {
unsigned char cmd_len;
unsigned char cmnd[MAX_COMMAND_SIZE];
struct scsi_data_buffer sdb;
+ struct request *next_rq;
/* new command support */
struct scatterlist sense_sgl;
--
1.5.3.1
next prev parent reply other threads:[~2007-11-08 17:03 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-06 18:04 [0/3] Last 3 patches for bidi support Boaz Harrosh
2007-11-06 18:16 ` [PATCH 1/3] scsi_tgt_lib: Use scsi_init_io instead of scsi_alloc_sgtable Boaz Harrosh
2007-11-08 3:13 ` FUJITA Tomonori
2007-11-08 8:32 ` Benny Halevy
2007-11-08 13:04 ` FUJITA Tomonori
2007-11-08 14:01 ` Boaz Harrosh
2007-11-08 14:20 ` FUJITA Tomonori
2007-11-06 18:19 ` [PATCH 2/3] scsi_data_buffer Boaz Harrosh
2007-11-08 3:14 ` FUJITA Tomonori
2007-11-08 9:24 ` Boaz Harrosh
2007-11-08 13:03 ` FUJITA Tomonori
2007-11-08 13:53 ` Boaz Harrosh
2007-11-08 13:44 ` Boaz Harrosh
2007-11-08 13:54 ` Jens Axboe
2007-11-08 14:17 ` Boaz Harrosh
2007-11-06 18:23 ` [PATCH 3/3] SCSI: bidi support Boaz Harrosh
2007-11-06 18:25 ` [0/3] Last 3 patches for " Mike Christie
2007-11-06 18:38 ` Boaz Harrosh
2007-11-08 3:13 ` FUJITA Tomonori
2007-11-08 16:49 ` [0/4 ver2] " Boaz Harrosh
2007-11-08 16:56 ` [PATCH 1/4] sr/sd: Remove dead code Boaz Harrosh
2007-11-08 16:57 ` [PATCH 2/4] tgt: Use scsi_init_io instead of scsi_alloc_sgtable Boaz Harrosh
2007-11-08 16:59 ` [PATCH 3/4] scsi_data_buffer Boaz Harrosh
2007-11-13 6:06 ` Andrew Morton
2007-11-13 6:40 ` FUJITA Tomonori
2007-11-13 7:07 ` Andrew Morton
2007-11-13 7:26 ` FUJITA Tomonori
2007-11-13 9:17 ` Boaz Harrosh
2007-11-08 17:03 ` Boaz Harrosh [this message]
2007-11-09 21:15 ` [PATCH 4/4] SCSI: bidi support Kiyoshi Ueda
[not found] ` <47383020.8010108@panasas.com>
2007-11-12 19:52 ` Kiyoshi Ueda
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47334156.8050105@panasas.com \
--to=bharrosh@panasas.com \
--cc=James.Bottomley@SteelEye.com \
--cc=akpm@osdl.org \
--cc=bhalevy@panasas.com \
--cc=fujita.tomonori@lab.ntt.co.jp \
--cc=linux-scsi@vger.kernel.org \
--cc=pw@osc.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).