From d285203cf647d7c97db3a1c33794315c9008593f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 17 Jan 2014 12:06:53 +0100 Subject: scsi: add support for a blk-mq based I/O path. This patch adds support for an alternate I/O path in the scsi midlayer which uses the blk-mq infrastructure instead of the legacy request code. Use of blk-mq is fully transparent to drivers, although for now a host template field is provided to opt out of blk-mq usage in case any unforseen incompatibilities arise. In general replacing the legacy request code with blk-mq is a simple and mostly mechanical transformation. The biggest exception is the new code that deals with the fact the I/O submissions in blk-mq must happen from process context, which slightly complicates the I/O completion handler. The second biggest differences is that blk-mq is build around the concept of preallocated requests that also include driver specific data, which in SCSI context means the scsi_cmnd structure. This completely avoids dynamic memory allocations for the fast path through I/O submission. Due the preallocated requests the MQ code path exclusively uses the host-wide shared tag allocator instead of a per-LUN one. This only affects drivers actually using the block layer provided tag allocator instead of their own. Unlike the old path blk-mq always provides a tag, although drivers don't have to use it. For now the blk-mq path is disable by defauly and must be enabled using the "use_blk_mq" module parameter. Once the remaining work in the block layer to make blk-mq more suitable for slow devices is complete I hope to make it the default and eventually even remove the old code path. Based on the earlier scsi-mq prototype by Nicholas Bellinger. Thanks to Bart Van Assche and Robert Elliot for testing, benchmarking and various sugestions and code contributions. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Reviewed-by: Webb Scales Acked-by: Jens Axboe Tested-by: Bart Van Assche Tested-by: Robert Elliott --- drivers/scsi/hosts.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/hosts.c') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 0632eee82620..6de80e352871 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -213,9 +213,24 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, goto fail; } + if (shost_use_blk_mq(shost)) { + error = scsi_mq_setup_tags(shost); + if (error) + goto fail; + } + + /* + * Note that we allocate the freelist even for the MQ case for now, + * as we need a command set aside for scsi_reset_provider. Having + * the full host freelist and one command available for that is a + * little heavy-handed, but avoids introducing a special allocator + * just for this. Eventually the structure of scsi_reset_provider + * will need a major overhaul. + */ error = scsi_setup_command_freelist(shost); if (error) - goto fail; + goto out_destroy_tags; + if (!shost->shost_gendev.parent) shost->shost_gendev.parent = dev ? dev : &platform_bus; @@ -226,7 +241,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, error = device_add(&shost->shost_gendev); if (error) - goto out; + goto out_destroy_freelist; pm_runtime_set_active(&shost->shost_gendev); pm_runtime_enable(&shost->shost_gendev); @@ -279,8 +294,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, device_del(&shost->shost_dev); out_del_gendev: device_del(&shost->shost_gendev); - out: + out_destroy_freelist: scsi_destroy_command_freelist(shost); + out_destroy_tags: + if (shost_use_blk_mq(shost)) + scsi_mq_destroy_tags(shost); fail: return error; } @@ -309,8 +327,13 @@ static void scsi_host_dev_release(struct device *dev) } scsi_destroy_command_freelist(shost); - if (shost->bqt) - blk_free_tags(shost->bqt); + if (shost_use_blk_mq(shost)) { + if (shost->tag_set.tags) + scsi_mq_destroy_tags(shost); + } else { + if (shost->bqt) + blk_free_tags(shost->bqt); + } kfree(shost->shost_data); @@ -436,6 +459,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) else shost->dma_boundary = 0xffffffff; + shost->use_blk_mq = scsi_use_blk_mq && !shost->hostt->disable_blk_mq; + device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); shost->shost_gendev.bus = &scsi_bus_type; -- cgit v1.2.1