162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * BSG helper library 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 James Smart, Emulex Corporation 662306a36Sopenharmony_ci * Copyright (C) 2011 Red Hat, Inc. All rights reserved. 762306a36Sopenharmony_ci * Copyright (C) 2011 Mike Christie 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/bsg.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/blk-mq.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/scatterlist.h> 1462306a36Sopenharmony_ci#include <linux/bsg-lib.h> 1562306a36Sopenharmony_ci#include <linux/export.h> 1662306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 1762306a36Sopenharmony_ci#include <scsi/sg.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define uptr64(val) ((void __user *)(uintptr_t)(val)) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct bsg_set { 2262306a36Sopenharmony_ci struct blk_mq_tag_set tag_set; 2362306a36Sopenharmony_ci struct bsg_device *bd; 2462306a36Sopenharmony_ci bsg_job_fn *job_fn; 2562306a36Sopenharmony_ci bsg_timeout_fn *timeout_fn; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int bsg_transport_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr, 2962306a36Sopenharmony_ci bool open_for_write, unsigned int timeout) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct bsg_job *job; 3262306a36Sopenharmony_ci struct request *rq; 3362306a36Sopenharmony_ci struct bio *bio; 3462306a36Sopenharmony_ci void *reply; 3562306a36Sopenharmony_ci int ret; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (hdr->protocol != BSG_PROTOCOL_SCSI || 3862306a36Sopenharmony_ci hdr->subprotocol != BSG_SUB_PROTOCOL_SCSI_TRANSPORT) 3962306a36Sopenharmony_ci return -EINVAL; 4062306a36Sopenharmony_ci if (!capable(CAP_SYS_RAWIO)) 4162306a36Sopenharmony_ci return -EPERM; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci rq = blk_mq_alloc_request(q, hdr->dout_xfer_len ? 4462306a36Sopenharmony_ci REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); 4562306a36Sopenharmony_ci if (IS_ERR(rq)) 4662306a36Sopenharmony_ci return PTR_ERR(rq); 4762306a36Sopenharmony_ci rq->timeout = timeout; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci job = blk_mq_rq_to_pdu(rq); 5062306a36Sopenharmony_ci reply = job->reply; 5162306a36Sopenharmony_ci memset(job, 0, sizeof(*job)); 5262306a36Sopenharmony_ci job->reply = reply; 5362306a36Sopenharmony_ci job->reply_len = SCSI_SENSE_BUFFERSIZE; 5462306a36Sopenharmony_ci job->dd_data = job + 1; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci job->request_len = hdr->request_len; 5762306a36Sopenharmony_ci job->request = memdup_user(uptr64(hdr->request), hdr->request_len); 5862306a36Sopenharmony_ci if (IS_ERR(job->request)) { 5962306a36Sopenharmony_ci ret = PTR_ERR(job->request); 6062306a36Sopenharmony_ci goto out_free_rq; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (hdr->dout_xfer_len && hdr->din_xfer_len) { 6462306a36Sopenharmony_ci job->bidi_rq = blk_mq_alloc_request(rq->q, REQ_OP_DRV_IN, 0); 6562306a36Sopenharmony_ci if (IS_ERR(job->bidi_rq)) { 6662306a36Sopenharmony_ci ret = PTR_ERR(job->bidi_rq); 6762306a36Sopenharmony_ci goto out_free_job_request; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ret = blk_rq_map_user(rq->q, job->bidi_rq, NULL, 7162306a36Sopenharmony_ci uptr64(hdr->din_xferp), hdr->din_xfer_len, 7262306a36Sopenharmony_ci GFP_KERNEL); 7362306a36Sopenharmony_ci if (ret) 7462306a36Sopenharmony_ci goto out_free_bidi_rq; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci job->bidi_bio = job->bidi_rq->bio; 7762306a36Sopenharmony_ci } else { 7862306a36Sopenharmony_ci job->bidi_rq = NULL; 7962306a36Sopenharmony_ci job->bidi_bio = NULL; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ret = 0; 8362306a36Sopenharmony_ci if (hdr->dout_xfer_len) { 8462306a36Sopenharmony_ci ret = blk_rq_map_user(rq->q, rq, NULL, uptr64(hdr->dout_xferp), 8562306a36Sopenharmony_ci hdr->dout_xfer_len, GFP_KERNEL); 8662306a36Sopenharmony_ci } else if (hdr->din_xfer_len) { 8762306a36Sopenharmony_ci ret = blk_rq_map_user(rq->q, rq, NULL, uptr64(hdr->din_xferp), 8862306a36Sopenharmony_ci hdr->din_xfer_len, GFP_KERNEL); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (ret) 9262306a36Sopenharmony_ci goto out_unmap_bidi_rq; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci bio = rq->bio; 9562306a36Sopenharmony_ci blk_execute_rq(rq, !(hdr->flags & BSG_FLAG_Q_AT_TAIL)); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * The assignments below don't make much sense, but are kept for 9962306a36Sopenharmony_ci * bug by bug backwards compatibility: 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci hdr->device_status = job->result & 0xff; 10262306a36Sopenharmony_ci hdr->transport_status = host_byte(job->result); 10362306a36Sopenharmony_ci hdr->driver_status = 0; 10462306a36Sopenharmony_ci hdr->info = 0; 10562306a36Sopenharmony_ci if (hdr->device_status || hdr->transport_status || hdr->driver_status) 10662306a36Sopenharmony_ci hdr->info |= SG_INFO_CHECK; 10762306a36Sopenharmony_ci hdr->response_len = 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (job->result < 0) { 11062306a36Sopenharmony_ci /* we're only returning the result field in the reply */ 11162306a36Sopenharmony_ci job->reply_len = sizeof(u32); 11262306a36Sopenharmony_ci ret = job->result; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (job->reply_len && hdr->response) { 11662306a36Sopenharmony_ci int len = min(hdr->max_response_len, job->reply_len); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (copy_to_user(uptr64(hdr->response), job->reply, len)) 11962306a36Sopenharmony_ci ret = -EFAULT; 12062306a36Sopenharmony_ci else 12162306a36Sopenharmony_ci hdr->response_len = len; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* we assume all request payload was transferred, residual == 0 */ 12562306a36Sopenharmony_ci hdr->dout_resid = 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (job->bidi_rq) { 12862306a36Sopenharmony_ci unsigned int rsp_len = job->reply_payload.payload_len; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (WARN_ON(job->reply_payload_rcv_len > rsp_len)) 13162306a36Sopenharmony_ci hdr->din_resid = 0; 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci hdr->din_resid = rsp_len - job->reply_payload_rcv_len; 13462306a36Sopenharmony_ci } else { 13562306a36Sopenharmony_ci hdr->din_resid = 0; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci blk_rq_unmap_user(bio); 13962306a36Sopenharmony_ciout_unmap_bidi_rq: 14062306a36Sopenharmony_ci if (job->bidi_rq) 14162306a36Sopenharmony_ci blk_rq_unmap_user(job->bidi_bio); 14262306a36Sopenharmony_ciout_free_bidi_rq: 14362306a36Sopenharmony_ci if (job->bidi_rq) 14462306a36Sopenharmony_ci blk_mq_free_request(job->bidi_rq); 14562306a36Sopenharmony_ciout_free_job_request: 14662306a36Sopenharmony_ci kfree(job->request); 14762306a36Sopenharmony_ciout_free_rq: 14862306a36Sopenharmony_ci blk_mq_free_request(rq); 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/** 15362306a36Sopenharmony_ci * bsg_teardown_job - routine to teardown a bsg job 15462306a36Sopenharmony_ci * @kref: kref inside bsg_job that is to be torn down 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_cistatic void bsg_teardown_job(struct kref *kref) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct bsg_job *job = container_of(kref, struct bsg_job, kref); 15962306a36Sopenharmony_ci struct request *rq = blk_mq_rq_from_pdu(job); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci put_device(job->dev); /* release reference for the request */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci kfree(job->request_payload.sg_list); 16462306a36Sopenharmony_ci kfree(job->reply_payload.sg_list); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci blk_mq_end_request(rq, BLK_STS_OK); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid bsg_job_put(struct bsg_job *job) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci kref_put(&job->kref, bsg_teardown_job); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bsg_job_put); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ciint bsg_job_get(struct bsg_job *job) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return kref_get_unless_zero(&job->kref); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bsg_job_get); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/** 18262306a36Sopenharmony_ci * bsg_job_done - completion routine for bsg requests 18362306a36Sopenharmony_ci * @job: bsg_job that is complete 18462306a36Sopenharmony_ci * @result: job reply result 18562306a36Sopenharmony_ci * @reply_payload_rcv_len: length of payload recvd 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * The LLD should call this when the bsg job has completed. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_civoid bsg_job_done(struct bsg_job *job, int result, 19062306a36Sopenharmony_ci unsigned int reply_payload_rcv_len) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct request *rq = blk_mq_rq_from_pdu(job); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci job->result = result; 19562306a36Sopenharmony_ci job->reply_payload_rcv_len = reply_payload_rcv_len; 19662306a36Sopenharmony_ci if (likely(!blk_should_fake_timeout(rq->q))) 19762306a36Sopenharmony_ci blk_mq_complete_request(rq); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bsg_job_done); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/** 20262306a36Sopenharmony_ci * bsg_complete - softirq done routine for destroying the bsg requests 20362306a36Sopenharmony_ci * @rq: BSG request that holds the job to be destroyed 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cistatic void bsg_complete(struct request *rq) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct bsg_job *job = blk_mq_rq_to_pdu(rq); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci bsg_job_put(job); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int bsg_map_buffer(struct bsg_buffer *buf, struct request *req) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci BUG_ON(!req->nr_phys_segments); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci buf->sg_list = kmalloc(sz, GFP_KERNEL); 21962306a36Sopenharmony_ci if (!buf->sg_list) 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci sg_init_table(buf->sg_list, req->nr_phys_segments); 22262306a36Sopenharmony_ci buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list); 22362306a36Sopenharmony_ci buf->payload_len = blk_rq_bytes(req); 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * bsg_prepare_job - create the bsg_job structure for the bsg request 22962306a36Sopenharmony_ci * @dev: device that is being sent the bsg request 23062306a36Sopenharmony_ci * @req: BSG request that needs a job structure 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_cistatic bool bsg_prepare_job(struct device *dev, struct request *req) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct bsg_job *job = blk_mq_rq_to_pdu(req); 23562306a36Sopenharmony_ci int ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci job->timeout = req->timeout; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (req->bio) { 24062306a36Sopenharmony_ci ret = bsg_map_buffer(&job->request_payload, req); 24162306a36Sopenharmony_ci if (ret) 24262306a36Sopenharmony_ci goto failjob_rls_job; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci if (job->bidi_rq) { 24562306a36Sopenharmony_ci ret = bsg_map_buffer(&job->reply_payload, job->bidi_rq); 24662306a36Sopenharmony_ci if (ret) 24762306a36Sopenharmony_ci goto failjob_rls_rqst_payload; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci job->dev = dev; 25062306a36Sopenharmony_ci /* take a reference for the request */ 25162306a36Sopenharmony_ci get_device(job->dev); 25262306a36Sopenharmony_ci kref_init(&job->kref); 25362306a36Sopenharmony_ci return true; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cifailjob_rls_rqst_payload: 25662306a36Sopenharmony_ci kfree(job->request_payload.sg_list); 25762306a36Sopenharmony_cifailjob_rls_job: 25862306a36Sopenharmony_ci job->result = -ENOMEM; 25962306a36Sopenharmony_ci return false; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/** 26362306a36Sopenharmony_ci * bsg_queue_rq - generic handler for bsg requests 26462306a36Sopenharmony_ci * @hctx: hardware queue 26562306a36Sopenharmony_ci * @bd: queue data 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * On error the create_bsg_job function should return a -Exyz error value 26862306a36Sopenharmony_ci * that will be set to ->result. 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Drivers/subsys should pass this to the queue init function. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cistatic blk_status_t bsg_queue_rq(struct blk_mq_hw_ctx *hctx, 27362306a36Sopenharmony_ci const struct blk_mq_queue_data *bd) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 27662306a36Sopenharmony_ci struct device *dev = q->queuedata; 27762306a36Sopenharmony_ci struct request *req = bd->rq; 27862306a36Sopenharmony_ci struct bsg_set *bset = 27962306a36Sopenharmony_ci container_of(q->tag_set, struct bsg_set, tag_set); 28062306a36Sopenharmony_ci blk_status_t sts = BLK_STS_IOERR; 28162306a36Sopenharmony_ci int ret; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci blk_mq_start_request(req); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!get_device(dev)) 28662306a36Sopenharmony_ci return BLK_STS_IOERR; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!bsg_prepare_job(dev, req)) 28962306a36Sopenharmony_ci goto out; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ret = bset->job_fn(blk_mq_rq_to_pdu(req)); 29262306a36Sopenharmony_ci if (!ret) 29362306a36Sopenharmony_ci sts = BLK_STS_OK; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciout: 29662306a36Sopenharmony_ci put_device(dev); 29762306a36Sopenharmony_ci return sts; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* called right after the request is allocated for the request_queue */ 30162306a36Sopenharmony_cistatic int bsg_init_rq(struct blk_mq_tag_set *set, struct request *req, 30262306a36Sopenharmony_ci unsigned int hctx_idx, unsigned int numa_node) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct bsg_job *job = blk_mq_rq_to_pdu(req); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci job->reply = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); 30762306a36Sopenharmony_ci if (!job->reply) 30862306a36Sopenharmony_ci return -ENOMEM; 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void bsg_exit_rq(struct blk_mq_tag_set *set, struct request *req, 31362306a36Sopenharmony_ci unsigned int hctx_idx) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct bsg_job *job = blk_mq_rq_to_pdu(req); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci kfree(job->reply); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_civoid bsg_remove_queue(struct request_queue *q) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci if (q) { 32362306a36Sopenharmony_ci struct bsg_set *bset = 32462306a36Sopenharmony_ci container_of(q->tag_set, struct bsg_set, tag_set); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci bsg_unregister_queue(bset->bd); 32762306a36Sopenharmony_ci blk_mq_destroy_queue(q); 32862306a36Sopenharmony_ci blk_put_queue(q); 32962306a36Sopenharmony_ci blk_mq_free_tag_set(&bset->tag_set); 33062306a36Sopenharmony_ci kfree(bset); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bsg_remove_queue); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic enum blk_eh_timer_return bsg_timeout(struct request *rq) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct bsg_set *bset = 33862306a36Sopenharmony_ci container_of(rq->q->tag_set, struct bsg_set, tag_set); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (!bset->timeout_fn) 34162306a36Sopenharmony_ci return BLK_EH_DONE; 34262306a36Sopenharmony_ci return bset->timeout_fn(rq); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic const struct blk_mq_ops bsg_mq_ops = { 34662306a36Sopenharmony_ci .queue_rq = bsg_queue_rq, 34762306a36Sopenharmony_ci .init_request = bsg_init_rq, 34862306a36Sopenharmony_ci .exit_request = bsg_exit_rq, 34962306a36Sopenharmony_ci .complete = bsg_complete, 35062306a36Sopenharmony_ci .timeout = bsg_timeout, 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/** 35462306a36Sopenharmony_ci * bsg_setup_queue - Create and add the bsg hooks so we can receive requests 35562306a36Sopenharmony_ci * @dev: device to attach bsg device to 35662306a36Sopenharmony_ci * @name: device to give bsg device 35762306a36Sopenharmony_ci * @job_fn: bsg job handler 35862306a36Sopenharmony_ci * @timeout: timeout handler function pointer 35962306a36Sopenharmony_ci * @dd_job_size: size of LLD data needed for each job 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_cistruct request_queue *bsg_setup_queue(struct device *dev, const char *name, 36262306a36Sopenharmony_ci bsg_job_fn *job_fn, bsg_timeout_fn *timeout, int dd_job_size) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct bsg_set *bset; 36562306a36Sopenharmony_ci struct blk_mq_tag_set *set; 36662306a36Sopenharmony_ci struct request_queue *q; 36762306a36Sopenharmony_ci int ret = -ENOMEM; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci bset = kzalloc(sizeof(*bset), GFP_KERNEL); 37062306a36Sopenharmony_ci if (!bset) 37162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci bset->job_fn = job_fn; 37462306a36Sopenharmony_ci bset->timeout_fn = timeout; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci set = &bset->tag_set; 37762306a36Sopenharmony_ci set->ops = &bsg_mq_ops; 37862306a36Sopenharmony_ci set->nr_hw_queues = 1; 37962306a36Sopenharmony_ci set->queue_depth = 128; 38062306a36Sopenharmony_ci set->numa_node = NUMA_NO_NODE; 38162306a36Sopenharmony_ci set->cmd_size = sizeof(struct bsg_job) + dd_job_size; 38262306a36Sopenharmony_ci set->flags = BLK_MQ_F_NO_SCHED | BLK_MQ_F_BLOCKING; 38362306a36Sopenharmony_ci if (blk_mq_alloc_tag_set(set)) 38462306a36Sopenharmony_ci goto out_tag_set; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci q = blk_mq_init_queue(set); 38762306a36Sopenharmony_ci if (IS_ERR(q)) { 38862306a36Sopenharmony_ci ret = PTR_ERR(q); 38962306a36Sopenharmony_ci goto out_queue; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci q->queuedata = dev; 39362306a36Sopenharmony_ci blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci bset->bd = bsg_register_queue(q, dev, name, bsg_transport_sg_io_fn); 39662306a36Sopenharmony_ci if (IS_ERR(bset->bd)) { 39762306a36Sopenharmony_ci ret = PTR_ERR(bset->bd); 39862306a36Sopenharmony_ci goto out_cleanup_queue; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return q; 40262306a36Sopenharmony_ciout_cleanup_queue: 40362306a36Sopenharmony_ci blk_mq_destroy_queue(q); 40462306a36Sopenharmony_ci blk_put_queue(q); 40562306a36Sopenharmony_ciout_queue: 40662306a36Sopenharmony_ci blk_mq_free_tag_set(set); 40762306a36Sopenharmony_ciout_tag_set: 40862306a36Sopenharmony_ci kfree(bset); 40962306a36Sopenharmony_ci return ERR_PTR(ret); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bsg_setup_queue); 412