Skip to contentSkip to conversation

scsi tgt: export scsi-ml functions needed by tgt_scsi_lib and its LLDs

PATCH In review Mike Christie 1 participant 1 message Feb 16, 2006 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/6 scsi tgt: export scsi-ml functions needed by tgt_scsi_lib and its LLDs

Subject: [PATCH] scsi-ml: export scsi-ml functions needed by tgt_scsi_lib and its LLDs

This patch contains the needed changes to the scsi-ml to support targets.

Note, per the last review we moved almost all the fields we added to the scsi_cmnd to our internal data structure which we are going to try and kill off when we can replace it with support from other parts of the kernel.

The one field we left on was the offset variable. This is needed to handle the case where the target gets request that is so large that it cannot execute it in one dma operation. So max_secotors or a segment limit may limit the size of the transfer. In this case our tgt core code will break up the command into managable transfers and send them to the LLD one at a time. The offset is then used to tell the LLD where in the command we are at. Is there another field on the scsi_cmd for that?

---

 drivers/scsi/hosts.c     |    5 +++
 drivers/scsi/scsi.c      |   91 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/scsi_lib.c  |   33 ++++++++++++-----
 include/scsi/scsi_cmnd.h |    8 ++++
 include/scsi/scsi_host.h |   40 ++++++++++++++++++++
 5 files changed, 168 insertions(+), 9 deletions(-)

4ab7d1a25185748e2aaf86b30784c280bbf5de2b

drivers/scsi/hosts.c +5 -0
index ef57f25..a122624 100644
@@ -264,6 +264,11 @@ static void scsi_host_dev_release(struct
 	if (shost->work_q)
 		destroy_workqueue(shost->work_q);
 
+	if (shost->uspace_req_q) {
+		kfree(shost->uspace_req_q->queuedata);
+		scsi_free_queue(shost->uspace_req_q);
+	}
+
 	scsi_destroy_command_freelist(shost);
 	kfree(shost->shost_data);
 
drivers/scsi/scsi.c +91 -0

103 lines not on this page · raw message

drivers/scsi/scsi_lib.c +24 -9
index 5ac8749..2dcc500 100644
@@ -802,7 +802,7 @@ static struct scsi_cmnd *scsi_end_reques
 	return NULL;
 }
 
-static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 {
 	struct scsi_host_sg_pool *sgp;
 	struct scatterlist *sgl;
@@ -843,7 +843,9 @@ static struct scatterlist *scsi_alloc_sg
 	return sgl;
 }
 
-static void scsi_free_sgtable(struct scatterlist *sgl, int index)
+EXPORT_SYMBOL(scsi_alloc_sgtable);
+
+void scsi_free_sgtable(struct scatterlist *sgl, int index)
 {
 	struct scsi_host_sg_pool *sgp;
 
@@ -853,6 +855,8 @@ static void scsi_free_sgtable(struct sca
 	mempool_free(sgl, sgp->pool);
 }
 
+EXPORT_SYMBOL(scsi_free_sgtable);
+
 /*
  * Function:    scsi_release_buffers()
  *
@@ -1685,29 +1689,40 @@ u64 scsi_calculate_bounce_limit(struct S
 }
 EXPORT_SYMBOL(scsi_calculate_bounce_limit);
 
-struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+					 request_fn_proc *request_fn)
 {
-	struct Scsi_Host *shost = sdev->host;
 	struct request_queue *q;
 
-	q = blk_init_queue(scsi_request_fn, NULL);
+	q = blk_init_queue(request_fn, NULL);
 	if (!q)
 		return NULL;
 
-	blk_queue_prep_rq(q, scsi_prep_fn);
-
 	blk_queue_max_hw_segments(q, shost->sg_tablesize);
 	blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
 	blk_queue_max_sectors(q, shost->max_sectors);
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
 	blk_queue_segment_boundary(q, shost->dma_boundary);
-	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
-	blk_queue_softirq_done(q, scsi_softirq_done);
 
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 	return q;
 }
+EXPORT_SYMBOL(__scsi_alloc_queue);
+
+struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+{
+	struct request_queue *q;
+
+	q = __scsi_alloc_queue(sdev->host, scsi_request_fn);
+	if (!q)
+		return NULL;
+
+	blk_queue_prep_rq(q, scsi_prep_fn);
+	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+	blk_queue_softirq_done(q, scsi_softirq_done);
+	return q;
+}
 
 void scsi_free_queue(struct request_queue *q)
 {
include/scsi/scsi_cmnd.h +8 -0
index 1ace1b9..8f64515 100644
@@ -8,6 +8,7 @@
 
 struct request;
 struct scatterlist;
+struct Scsi_Host;
 struct scsi_device;
 struct scsi_request;
 
@@ -84,6 +85,8 @@ struct scsi_cmnd {
 	unsigned short sglist_len;	/* size of malloc'd scatter-gather list */
 	unsigned bufflen;	/* Size of data buffer */
 	void *buffer;		/* Data buffer */
+	/* offset in cmd we are at (for multi-transfer tgt cmds) */
+	unsigned offset;
 
 	unsigned underflow;	/* Return error if less than
 				   this amount is transferred */
@@ -147,9 +150,14 @@ struct scsi_cmnd {
 #define SCSI_STATE_MLQUEUE         0x100b
 
 
+extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
+					       enum dma_data_direction, gfp_t);
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
+extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
 extern void scsi_put_command(struct scsi_cmnd *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
+extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
+extern void scsi_free_sgtable(struct scatterlist *, int);
 
 #endif /* _SCSI_SCSI_CMND_H */
include/scsi/scsi_host.h +40 -0
index 8279929..8b799db 100644
@@ -7,6 +7,7 @@
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
 
+struct request_queue;
 struct block_device;
 struct completion;
 struct module;
@@ -123,6 +124,36 @@ struct scsi_host_template {
 			     void (*done)(struct scsi_cmnd *));
 
 	/*
+	 * The transfer functions are used to queue a scsi command to
+	 * the LLD. When the driver is finished processing the command
+	 * the done callback is invoked.
+	 *
+	 * return values: see queuecommand
+	 *
+	 * If the LLD accepts the cmd, it should set the result to an
+	 * appropriate value when completed before calling the done function.
+	 *
+	 * STATUS: REQUIRED FOR TARGET DRIVERS
+	 */
+	/* TODO: rename */
+	int (* transfer_response)(struct scsi_cmnd *,
+				  void (*done)(struct scsi_cmnd *));
+	/*
+	 * This is called to inform the LLD to transfer cmd->request_bufflen
+	 * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
+	 * speciefies the number of scatterlist entried in the command
+	 * and cmd->request_buffer contains the scatterlist.
+	 *
+	 * If the command cannot be processed in one transfer_data call
+	 * becuase a scatterlist within the LLD's limits cannot be
+	 * created then transfer_data will be called multiple times.
+	 * It is initially called from process context, and later
+	 * calls are from the interrup context.
+	 */
+	int (* transfer_data)(struct scsi_cmnd *,
+			      void (*done)(struct scsi_cmnd *));
+
+	/*
 	 * This is an error handling strategy routine.  You don't need to
 	 * define one of these if you don't want to - there is a default
 	 * routine that is present that should work in most cases.  For those
@@ -572,6 +603,12 @@ struct Scsi_Host {
 	 */
 	unsigned int max_host_blocked;
 
+	/*
+	 * q used for scsi_tgt msgs, async events or any other requests that
+	 * need to be processed in userspace
+ 	 */
+	struct request_queue *uspace_req_q;
+
 	/* legacy crap */
 	unsigned long base;
 	unsigned long io_port;
@@ -674,6 +711,9 @@ extern void scsi_unblock_requests(struct
 extern void scsi_block_requests(struct Scsi_Host *);
 
 struct class_container;
+
+extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+					     void (*) (struct request_queue *));
 /*
  * These two functions are used to allocate and free a pseudo device
  * which will connect to the host adapter itself rather than any
Signature · 1 line
1.1.3