Skip to content

Commit 27c7fa5

Browse files
committed
Merge branch 'for-7.1/block' into for-next
* for-7.1/block: scsi: bsg: add io_uring passthrough handler bsg: add io_uring command support to generic layer bsg: add bsg_uring_cmd uapi structure
2 parents 5c72e4d + 7b6d325 commit 27c7fa5

5 files changed

Lines changed: 288 additions & 4 deletions

File tree

block/bsg-lib.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
393393

394394
blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
395395

396-
bset->bd = bsg_register_queue(q, dev, name, bsg_transport_sg_io_fn);
396+
bset->bd = bsg_register_queue(q, dev, name, bsg_transport_sg_io_fn, NULL);
397397
if (IS_ERR(bset->bd)) {
398398
ret = PTR_ERR(bset->bd);
399399
goto out_cleanup_queue;

block/bsg.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/idr.h>
1313
#include <linux/bsg.h>
1414
#include <linux/slab.h>
15+
#include <linux/io_uring/cmd.h>
1516

1617
#include <scsi/scsi.h>
1718
#include <scsi/scsi_ioctl.h>
@@ -28,6 +29,7 @@ struct bsg_device {
2829
unsigned int timeout;
2930
unsigned int reserved_size;
3031
bsg_sg_io_fn *sg_io_fn;
32+
bsg_uring_cmd_fn *uring_cmd_fn;
3133
};
3234

3335
static inline struct bsg_device *to_bsg_device(struct inode *inode)
@@ -158,11 +160,38 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
158160
}
159161
}
160162

163+
static int bsg_check_uring_features(unsigned int issue_flags)
164+
{
165+
/* BSG passthrough requires big SQE/CQE support */
166+
if ((issue_flags & (IO_URING_F_SQE128|IO_URING_F_CQE32)) !=
167+
(IO_URING_F_SQE128|IO_URING_F_CQE32))
168+
return -EOPNOTSUPP;
169+
return 0;
170+
}
171+
172+
static int bsg_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags)
173+
{
174+
struct bsg_device *bd = to_bsg_device(file_inode(ioucmd->file));
175+
bool open_for_write = ioucmd->file->f_mode & FMODE_WRITE;
176+
struct request_queue *q = bd->queue;
177+
int ret;
178+
179+
ret = bsg_check_uring_features(issue_flags);
180+
if (ret)
181+
return ret;
182+
183+
if (!bd->uring_cmd_fn)
184+
return -EOPNOTSUPP;
185+
186+
return bd->uring_cmd_fn(q, ioucmd, issue_flags, open_for_write);
187+
}
188+
161189
static const struct file_operations bsg_fops = {
162190
.open = bsg_open,
163191
.release = bsg_release,
164192
.unlocked_ioctl = bsg_ioctl,
165193
.compat_ioctl = compat_ptr_ioctl,
194+
.uring_cmd = bsg_uring_cmd,
166195
.owner = THIS_MODULE,
167196
.llseek = default_llseek,
168197
};
@@ -187,7 +216,8 @@ void bsg_unregister_queue(struct bsg_device *bd)
187216
EXPORT_SYMBOL_GPL(bsg_unregister_queue);
188217

189218
struct bsg_device *bsg_register_queue(struct request_queue *q,
190-
struct device *parent, const char *name, bsg_sg_io_fn *sg_io_fn)
219+
struct device *parent, const char *name, bsg_sg_io_fn *sg_io_fn,
220+
bsg_uring_cmd_fn *uring_cmd_fn)
191221
{
192222
struct bsg_device *bd;
193223
int ret;
@@ -199,6 +229,7 @@ struct bsg_device *bsg_register_queue(struct request_queue *q,
199229
bd->reserved_size = INT_MAX;
200230
bd->queue = q;
201231
bd->sg_io_fn = sg_io_fn;
232+
bd->uring_cmd_fn = uring_cmd_fn;
202233

203234
ret = ida_alloc_max(&bsg_minor_ida, BSG_MAX_DEVS - 1, GFP_KERNEL);
204235
if (ret < 0) {

drivers/scsi/scsi_bsg.c

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
#include <linux/bsg.h>
3+
#include <linux/io_uring/cmd.h>
34
#include <scsi/scsi.h>
45
#include <scsi/scsi_ioctl.h>
56
#include <scsi/scsi_cmnd.h>
@@ -9,6 +10,178 @@
910

1011
#define uptr64(val) ((void __user *)(uintptr_t)(val))
1112

13+
/*
14+
* Per-command BSG SCSI PDU stored in io_uring_cmd.pdu[32].
15+
* Holds temporary state between submission, completion and task_work.
16+
*/
17+
struct scsi_bsg_uring_cmd_pdu {
18+
struct bio *bio; /* mapped user buffer, unmap in task work */
19+
struct request *req; /* block request, freed in task work */
20+
u64 response_addr; /* user space response buffer address */
21+
};
22+
static_assert(sizeof(struct scsi_bsg_uring_cmd_pdu) <= sizeof_field(struct io_uring_cmd, pdu));
23+
24+
static inline struct scsi_bsg_uring_cmd_pdu *scsi_bsg_uring_cmd_pdu(
25+
struct io_uring_cmd *ioucmd)
26+
{
27+
return io_uring_cmd_to_pdu(ioucmd, struct scsi_bsg_uring_cmd_pdu);
28+
}
29+
30+
/* Task work: build res2 (layout in uapi/linux/bsg.h) and copy sense to user. */
31+
static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw)
32+
{
33+
struct io_uring_cmd *ioucmd = io_uring_cmd_from_tw(tw_req);
34+
struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd);
35+
struct request *rq = pdu->req;
36+
struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
37+
u64 res2;
38+
int ret = 0;
39+
u8 driver_status = 0;
40+
u8 sense_len_wr = 0;
41+
42+
if (pdu->bio)
43+
blk_rq_unmap_user(pdu->bio);
44+
45+
if (scsi_status_is_check_condition(scmd->result)) {
46+
driver_status = DRIVER_SENSE;
47+
if (pdu->response_addr)
48+
sense_len_wr = min_t(u8, scmd->sense_len,
49+
SCSI_SENSE_BUFFERSIZE);
50+
}
51+
52+
if (sense_len_wr) {
53+
if (copy_to_user(uptr64(pdu->response_addr), scmd->sense_buffer,
54+
sense_len_wr))
55+
ret = -EFAULT;
56+
}
57+
58+
res2 = bsg_scsi_res2_build(status_byte(scmd->result), driver_status,
59+
host_byte(scmd->result), sense_len_wr,
60+
scmd->resid_len);
61+
62+
blk_mq_free_request(rq);
63+
io_uring_cmd_done32(ioucmd, ret, res2,
64+
IO_URING_CMD_TASK_WORK_ISSUE_FLAGS);
65+
}
66+
67+
static enum rq_end_io_ret scsi_bsg_uring_cmd_done(struct request *req,
68+
blk_status_t status,
69+
const struct io_comp_batch *iocb)
70+
{
71+
struct io_uring_cmd *ioucmd = req->end_io_data;
72+
73+
io_uring_cmd_do_in_task_lazy(ioucmd, scsi_bsg_uring_task_cb);
74+
return RQ_END_IO_NONE;
75+
}
76+
77+
static int scsi_bsg_map_user_buffer(struct request *req,
78+
struct io_uring_cmd *ioucmd,
79+
unsigned int issue_flags, gfp_t gfp_mask)
80+
{
81+
const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
82+
bool is_write = cmd->dout_xfer_len > 0;
83+
u64 buf_addr = is_write ? cmd->dout_xferp : cmd->din_xferp;
84+
unsigned long buf_len = is_write ? cmd->dout_xfer_len : cmd->din_xfer_len;
85+
struct iov_iter iter;
86+
int ret;
87+
88+
if (ioucmd->flags & IORING_URING_CMD_FIXED) {
89+
ret = io_uring_cmd_import_fixed(buf_addr, buf_len,
90+
is_write ? WRITE : READ,
91+
&iter, ioucmd, issue_flags);
92+
if (ret < 0)
93+
return ret;
94+
ret = blk_rq_map_user_iov(req->q, req, NULL, &iter, gfp_mask);
95+
} else {
96+
ret = blk_rq_map_user(req->q, req, NULL, uptr64(buf_addr),
97+
buf_len, gfp_mask);
98+
}
99+
100+
return ret;
101+
}
102+
103+
static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *ioucmd,
104+
unsigned int issue_flags, bool open_for_write)
105+
{
106+
struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd);
107+
const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
108+
struct scsi_cmnd *scmd;
109+
struct request *req;
110+
blk_mq_req_flags_t blk_flags = 0;
111+
gfp_t gfp_mask = GFP_KERNEL;
112+
int ret;
113+
114+
if (cmd->protocol != BSG_PROTOCOL_SCSI ||
115+
cmd->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
116+
return -EINVAL;
117+
118+
if (!cmd->request || cmd->request_len == 0)
119+
return -EINVAL;
120+
121+
if (cmd->dout_xfer_len && cmd->din_xfer_len) {
122+
pr_warn_once("BIDI support in bsg has been removed.\n");
123+
return -EOPNOTSUPP;
124+
}
125+
126+
if (cmd->dout_iovec_count > 0 || cmd->din_iovec_count > 0)
127+
return -EOPNOTSUPP;
128+
129+
if (issue_flags & IO_URING_F_NONBLOCK) {
130+
blk_flags = BLK_MQ_REQ_NOWAIT;
131+
gfp_mask = GFP_NOWAIT;
132+
}
133+
134+
req = scsi_alloc_request(q, cmd->dout_xfer_len ?
135+
REQ_OP_DRV_OUT : REQ_OP_DRV_IN, blk_flags);
136+
if (IS_ERR(req))
137+
return PTR_ERR(req);
138+
139+
scmd = blk_mq_rq_to_pdu(req);
140+
scmd->cmd_len = cmd->request_len;
141+
if (scmd->cmd_len > sizeof(scmd->cmnd)) {
142+
ret = -EINVAL;
143+
goto out_free_req;
144+
}
145+
scmd->allowed = SG_DEFAULT_RETRIES;
146+
147+
if (copy_from_user(scmd->cmnd, uptr64(cmd->request), cmd->request_len)) {
148+
ret = -EFAULT;
149+
goto out_free_req;
150+
}
151+
152+
if (!scsi_cmd_allowed(scmd->cmnd, open_for_write)) {
153+
ret = -EPERM;
154+
goto out_free_req;
155+
}
156+
157+
pdu->response_addr = cmd->response;
158+
scmd->sense_len = cmd->max_response_len ?
159+
min(cmd->max_response_len, SCSI_SENSE_BUFFERSIZE) : SCSI_SENSE_BUFFERSIZE;
160+
161+
if (cmd->dout_xfer_len || cmd->din_xfer_len) {
162+
ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags, gfp_mask);
163+
if (ret)
164+
goto out_free_req;
165+
pdu->bio = req->bio;
166+
} else {
167+
pdu->bio = NULL;
168+
}
169+
170+
req->timeout = cmd->timeout_ms ?
171+
msecs_to_jiffies(cmd->timeout_ms) : BLK_DEFAULT_SG_TIMEOUT;
172+
173+
req->end_io = scsi_bsg_uring_cmd_done;
174+
req->end_io_data = ioucmd;
175+
pdu->req = req;
176+
177+
blk_execute_rq_nowait(req, false);
178+
return -EIOCBQUEUED;
179+
180+
out_free_req:
181+
blk_mq_free_request(req);
182+
return ret;
183+
}
184+
12185
static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr,
13186
bool open_for_write, unsigned int timeout)
14187
{
@@ -99,5 +272,6 @@ static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr,
99272
struct bsg_device *scsi_bsg_register_queue(struct scsi_device *sdev)
100273
{
101274
return bsg_register_queue(sdev->request_queue, &sdev->sdev_gendev,
102-
dev_name(&sdev->sdev_gendev), scsi_bsg_sg_io_fn);
275+
dev_name(&sdev->sdev_gendev), scsi_bsg_sg_io_fn,
276+
scsi_bsg_uring_cmd);
103277
}

include/linux/bsg.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
struct bsg_device;
88
struct device;
99
struct request_queue;
10+
struct io_uring_cmd;
1011

1112
typedef int (bsg_sg_io_fn)(struct request_queue *, struct sg_io_v4 *hdr,
1213
bool open_for_write, unsigned int timeout);
1314

15+
typedef int (bsg_uring_cmd_fn)(struct request_queue *q, struct io_uring_cmd *ioucmd,
16+
unsigned int issue_flags, bool open_for_write);
17+
1418
struct bsg_device *bsg_register_queue(struct request_queue *q,
1519
struct device *parent, const char *name,
16-
bsg_sg_io_fn *sg_io_fn);
20+
bsg_sg_io_fn *sg_io_fn, bsg_uring_cmd_fn *uring_cmd_fn);
1721
void bsg_unregister_queue(struct bsg_device *bcd);
1822

1923
#endif /* _LINUX_BSG_H */

include/uapi/linux/bsg.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#ifndef _UAPIBSG_H
33
#define _UAPIBSG_H
44

5+
#ifdef __KERNEL__
6+
#include <linux/build_bug.h>
7+
#endif /* __KERNEL__ */
58
#include <linux/types.h>
69

710
#define BSG_PROTOCOL_SCSI 0
@@ -63,5 +66,77 @@ struct sg_io_v4 {
6366
__u32 padding;
6467
};
6568

69+
struct bsg_uring_cmd {
70+
__u64 request; /* [i], [*i] command descriptor address */
71+
__u32 request_len; /* [i] command descriptor length in bytes */
72+
__u32 protocol; /* [i] protocol type (BSG_PROTOCOL_*) */
73+
__u32 subprotocol; /* [i] subprotocol type (BSG_SUB_PROTOCOL_*) */
74+
__u32 max_response_len; /* [i] response buffer size in bytes */
75+
76+
__u64 response; /* [i], [*o] response data address */
77+
__u64 dout_xferp; /* [i], [*i] */
78+
__u32 dout_xfer_len; /* [i] bytes to be transferred to device */
79+
__u32 dout_iovec_count; /* [i] 0 -> "flat" dout transfer else
80+
* dout_xferp points to array of iovec
81+
*/
82+
__u64 din_xferp; /* [i], [*o] */
83+
__u32 din_xfer_len; /* [i] bytes to be transferred from device */
84+
__u32 din_iovec_count; /* [i] 0 -> "flat" din transfer */
85+
86+
__u32 timeout_ms; /* [i] timeout in milliseconds */
87+
__u8 reserved[12]; /* reserved for future extension */
88+
};
89+
90+
#ifdef __KERNEL__
91+
/* Must match IORING_OP_URING_CMD payload size (e.g. SQE128). */
92+
static_assert(sizeof(struct bsg_uring_cmd) == 80);
93+
#endif /* __KERNEL__ */
94+
95+
96+
/*
97+
* SCSI BSG io_uring completion (res2, 64-bit)
98+
*
99+
* When using BSG_PROTOCOL_SCSI + BSG_SUB_PROTOCOL_SCSI_CMD with
100+
* IORING_OP_URING_CMD, the completion queue entry (CQE) contains:
101+
* - result: errno (0 on success)
102+
* - res2: packed SCSI status
103+
*
104+
* res2 bit layout:
105+
* [0..7] device_status (SCSI status byte, e.g. CHECK_CONDITION)
106+
* [8..15] driver_status (e.g. DRIVER_SENSE when sense data is valid)
107+
* [16..23] host_status (e.g. DID_OK, DID_TIME_OUT)
108+
* [24..31] sense_len_wr (bytes of sense data written to response buffer)
109+
* [32..63] resid_len (residual transfer length)
110+
*/
111+
static inline __u8 bsg_scsi_res2_device_status(__u64 res2)
112+
{
113+
return res2 & 0xff;
114+
}
115+
static inline __u8 bsg_scsi_res2_driver_status(__u64 res2)
116+
{
117+
return res2 >> 8;
118+
}
119+
static inline __u8 bsg_scsi_res2_host_status(__u64 res2)
120+
{
121+
return res2 >> 16;
122+
}
123+
static inline __u8 bsg_scsi_res2_sense_len(__u64 res2)
124+
{
125+
return res2 >> 24;
126+
}
127+
static inline __u32 bsg_scsi_res2_resid_len(__u64 res2)
128+
{
129+
return res2 >> 32;
130+
}
131+
static inline __u64 bsg_scsi_res2_build(__u8 device_status, __u8 driver_status,
132+
__u8 host_status, __u8 sense_len_wr,
133+
__u32 resid_len)
134+
{
135+
return ((__u64)(__u32)(resid_len) << 32) |
136+
((__u64)sense_len_wr << 24) |
137+
((__u64)host_status << 16) |
138+
((__u64)driver_status << 8) |
139+
(__u64)device_status;
140+
}
66141

67142
#endif /* _UAPIBSG_H */

0 commit comments

Comments
 (0)