summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2012-10-04 11:07:52 +0200
committerJens Axboe <axboe@kernel.dk>2012-10-04 11:07:52 +0200
commit4c222addb496cb4c315c2f6e40b3eaad0a8831b8 (patch)
treeb9c32f7a74286b432347177c387c86451a0bd4ef
parent682d2507d559486bc8a19c654a9c5d947e76a9ab (diff)
mtip32xx: multiqueue
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c153
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h4
2 files changed, 75 insertions, 82 deletions
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index f946d31d6917..454a48d89bc2 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -31,6 +31,8 @@
#include <linux/module.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/numa.h>
#include <linux/bio.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
@@ -160,8 +162,7 @@ static void mtip_command_cleanup(struct driver_data *dd)
if (atomic_read(&command->active)
&& (command->async_callback)) {
- command->async_callback(command->async_data,
- -ENODEV);
+ command->async_callback(command->async_data, -ENODEV);
command->async_callback = NULL;
command->async_data = NULL;
}
@@ -603,8 +604,7 @@ static void mtip_timeout_function(unsigned long int data)
/* Call the async completion callback. */
if (likely(command->async_callback))
- command->async_callback(command->async_data,
- -EIO);
+ command->async_callback(command->async_data, -EIO);
command->async_callback = NULL;
command->comp_func = NULL;
@@ -2415,27 +2415,21 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd,
* be called with the data parameter passed as the callback data.
*
* @dd Pointer to the driver data structure.
- * @start First sector to read.
- * @nsect Number of sectors to read.
+ * @rq Request to read/write
* @nents Number of entries in scatter list for the read command.
- * @tag The tag of this read command.
- * @callback Pointer to the function that should be called
- * when the read completes.
- * @data Callback data passed to the callback function
- * when the read completes.
- * @dir Direction (read or write)
*
* return value
* None
*/
-static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
- int nsect, int nents, int tag, void *callback,
- void *data, int dir)
+static void mtip_hw_submit_io(struct driver_data *dd, struct request *rq,
+ unsigned int nents, struct blk_mq_hw_ctx *hctx)
{
struct host_to_dev_fis *fis;
struct mtip_port *port = dd->port;
- struct mtip_cmd *command = &port->commands[tag];
- int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ struct mtip_cmd *command = &port->commands[rq->tag];
+ int dma_dir = rq_data_dir(rq) == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ sector_t start = blk_rq_pos(rq);
+ unsigned int nsect = blk_rq_sectors(rq);
/* Map the scatter list for DMA access */
nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir);
@@ -2452,14 +2446,16 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
fis = command->command;
fis->type = 0x27;
fis->opts = 1 << 7;
- fis->command =
- (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE);
+ if (rq_data_dir(rq) == READ)
+ fis->command = ATA_CMD_FPDMA_READ;
+ else
+ fis->command = ATA_CMD_FPDMA_WRITE;
*((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF);
*((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF);
fis->device = 1 << 6;
fis->features = nsect & 0xFF;
fis->features_ex = (nsect >> 8) & 0xFF;
- fis->sect_count = ((tag << 3) | (tag >> 5));
+ fis->sect_count = ((rq->tag << 3) | (rq->tag >> 5));
fis->sect_cnt_ex = 0;
fis->control = 0;
fis->res2 = 0;
@@ -2484,23 +2480,22 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
* Set the completion function and data for the command passed
* from the upper layer.
*/
- command->async_data = data;
- command->async_callback = callback;
+ command->hctx = hctx;
+ command->async_data = rq;
+ command->async_callback = blk_mq_end_io;
/*
* To prevent this command from being issued
* if an internal command is in progress or error handling is active.
*/
if (port->flags & MTIP_PF_PAUSE_IO) {
- set_bit(tag, port->cmds_to_issue);
+ set_bit(rq->tag, port->cmds_to_issue);
set_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags);
return;
}
/* Issue the command to the hardware */
- mtip_issue_ncq_command(port, tag);
-
- return;
+ mtip_issue_ncq_command(port, rq->tag);
}
/*
@@ -3590,78 +3585,77 @@ static const struct block_device_operations mtip_block_ops = {
*
* @queue Pointer to the request queue. Unused other than to obtain
* the driver data structure.
- * @bio Pointer to the BIO.
+ * @rq Pointer to the request
*
*/
-static void mtip_make_request(struct request_queue *queue, struct bio *bio)
+static int mtip_submit_request(struct blk_mq_hw_ctx *hctx, struct request *rq)
{
- struct driver_data *dd = queue->queuedata;
+ struct driver_data *dd = hctx->queue->queuedata;
struct scatterlist *sg;
- struct bio_vec *bvec;
- int nents = 0;
- int tag = 0;
+ unsigned int nents;
if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) {
if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
&dd->dd_flag))) {
- bio_endio(bio, -ENXIO);
- return;
- }
- if (unlikely(test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))) {
- bio_endio(bio, -ENODATA);
- return;
+ return -ENXIO;
}
+ if (unlikely(test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag)))
+ return -ENODATA;
if (unlikely(test_bit(MTIP_DDF_WRITE_PROTECT_BIT,
&dd->dd_flag) &&
- bio_data_dir(bio))) {
- bio_endio(bio, -ENODATA);
- return;
- }
- if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))) {
- bio_endio(bio, -ENODATA);
- return;
+ (rq_data_dir(rq) == WRITE))) {
+ return -ENODATA;
}
+ if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)))
+ return -ENODATA;
}
- if (unlikely(!bio_has_data(bio))) {
- blk_queue_flush(queue, 0);
- bio_endio(bio, 0);
- return;
+ sg = mtip_hw_get_scatterlist(dd, &rq->tag);
+ if (!sg)
+ return -EIO;
+
+ if (unlikely(rq->nr_phys_segments > MTIP_MAX_SG)) {
+ dev_warn(&dd->pdev->dev,
+ "Maximum number of SGL entries exceeded\n");
+ mtip_hw_release_scatterlist(dd, rq->tag);
+ return -EIO;
}
- sg = mtip_hw_get_scatterlist(dd, &tag);
- if (likely(sg != NULL)) {
- blk_queue_bounce(queue, &bio);
+ /* Create the scatter list for this bio. */
+ nents = blk_rq_map_sg(hctx->queue, rq, sg);
- if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) {
- dev_warn(&dd->pdev->dev,
- "Maximum number of SGL entries exceeded\n");
- bio_io_error(bio);
- mtip_hw_release_scatterlist(dd, tag);
- return;
- }
+ /* Issue the read/write. */
+ mtip_hw_submit_io(dd, rq, nents, hctx);
+ return 0;
+}
- /* Create the scatter list for this bio. */
- bio_for_each_segment(bvec, bio, nents) {
- sg_set_page(&sg[nents],
- bvec->bv_page,
- bvec->bv_len,
- bvec->bv_offset);
- }
+static int mtip_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq)
+{
+ int ret;
+
+ ret = mtip_submit_request(hctx, rq);
+ if (!ret)
+ return BLK_MQ_RQ_QUEUE_OK;
- /* Issue the read/write. */
- mtip_hw_submit_io(dd,
- bio->bi_sector,
- bio_sectors(bio),
- nents,
- tag,
- bio_endio,
- bio,
- bio_data_dir(bio));
- } else
- bio_io_error(bio);
+ rq->errors = ret;
+ return BLK_MQ_RQ_QUEUE_ERROR;
}
+static struct blk_mq_ops mtip_mq_ops = {
+ .queue_rq = mtip_queue_rq,
+ .map_queue = blk_mq_map_single_queue,
+ .alloc_hctx = blk_mq_alloc_single_hw_queue,
+ .free_hctx = blk_mq_free_single_hw_queue,
+};
+
+static struct blk_mq_reg mtip_mq_reg = {
+ .ops = &mtip_mq_ops,
+ .nr_hw_queues = 1,
+ .queue_depth = 256,
+ .numa_node = NUMA_NO_NODE,
+ .flags = BLK_MQ_F_SHOULD_MERGE,
+};
+
/*
* Block layer initialization function.
*
@@ -3737,7 +3731,7 @@ static int mtip_block_initialize(struct driver_data *dd)
skip_create_disk:
/* Allocate the request queue. */
- dd->queue = blk_alloc_queue(GFP_KERNEL);
+ dd->queue = blk_mq_init_queue(&mtip_mq_reg);
if (dd->queue == NULL) {
dev_err(&dd->pdev->dev,
"Unable to allocate request queue\n");
@@ -3745,9 +3739,6 @@ skip_create_disk:
goto block_queue_alloc_init_error;
}
- /* Attach our request function to the request queue. */
- blk_queue_make_request(dd->queue, mtip_make_request);
-
dd->disk->queue = dd->queue;
dd->queue->queuedata = dd;
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index 18627a1d04c5..aa23c203e52a 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -295,7 +295,7 @@ struct mtip_cmd {
void *data,
int status);
/* Additional callback function that may be called by comp_func() */
- void (*async_callback)(void *data, int status);
+ void (*async_callback)(struct request *, int status);
void *async_data; /* Addl. data passed to async_callback() */
@@ -310,6 +310,8 @@ struct mtip_cmd {
unsigned long comp_time; /* command completion time, in jiffies */
atomic_t active; /* declares if this command sent to the drive. */
+
+ struct blk_mq_hw_ctx *hctx; /* block layer hw context used for io completion */
};
/* Structure used to describe a port. */