Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 40 additions & 22 deletions drivers/scsi/scsi_bsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,10 @@ static enum rq_end_io_ret scsi_bsg_uring_cmd_done(struct request *req,

static int scsi_bsg_map_user_buffer(struct request *req,
struct io_uring_cmd *ioucmd,
unsigned int issue_flags, gfp_t gfp_mask)
unsigned int issue_flags, gfp_t gfp_mask,
bool is_write, u64 buf_addr,
unsigned long buf_len)
{
const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
bool is_write = cmd->dout_xfer_len > 0;
u64 buf_addr = is_write ? cmd->dout_xferp : cmd->din_xferp;
unsigned long buf_len = is_write ? cmd->dout_xfer_len : cmd->din_xfer_len;
struct iov_iter iter;
int ret;

Expand All @@ -104,47 +102,61 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc
unsigned int issue_flags, bool open_for_write)
{
struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd);
const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
const struct bsg_uring_cmd *cmd =
io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
struct scsi_cmnd *scmd;
struct request *req;
blk_mq_req_flags_t blk_flags = 0;
gfp_t gfp_mask = GFP_KERNEL;
u64 request = READ_ONCE(cmd->request);
u32 request_len = READ_ONCE(cmd->request_len);
u32 protocol = READ_ONCE(cmd->protocol);
u32 subprotocol = READ_ONCE(cmd->subprotocol);
u32 max_response_len = READ_ONCE(cmd->max_response_len);
u64 response = READ_ONCE(cmd->response);
u64 dout_xferp = READ_ONCE(cmd->dout_xferp);
u32 dout_xfer_len = READ_ONCE(cmd->dout_xfer_len);
u32 dout_iovec_count = READ_ONCE(cmd->dout_iovec_count);
u64 din_xferp = READ_ONCE(cmd->din_xferp);
u32 din_xfer_len = READ_ONCE(cmd->din_xfer_len);
u32 din_iovec_count = READ_ONCE(cmd->din_iovec_count);
u32 timeout_ms = READ_ONCE(cmd->timeout_ms);
int ret;

if (cmd->protocol != BSG_PROTOCOL_SCSI ||
cmd->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
if (protocol != BSG_PROTOCOL_SCSI ||
subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
return -EINVAL;

if (!cmd->request || cmd->request_len == 0)
if (!request || request_len == 0)
return -EINVAL;

if (cmd->dout_xfer_len && cmd->din_xfer_len) {
if (dout_xfer_len && din_xfer_len) {
pr_warn_once("BIDI support in bsg has been removed.\n");
return -EOPNOTSUPP;
}

if (cmd->dout_iovec_count > 0 || cmd->din_iovec_count > 0)
if (dout_iovec_count > 0 || din_iovec_count > 0)
return -EOPNOTSUPP;

if (issue_flags & IO_URING_F_NONBLOCK) {
blk_flags = BLK_MQ_REQ_NOWAIT;
gfp_mask = GFP_NOWAIT;
}

req = scsi_alloc_request(q, cmd->dout_xfer_len ?
req = scsi_alloc_request(q, dout_xfer_len ?
REQ_OP_DRV_OUT : REQ_OP_DRV_IN, blk_flags);
if (IS_ERR(req))
return PTR_ERR(req);

scmd = blk_mq_rq_to_pdu(req);
if (cmd->request_len > sizeof(scmd->cmnd)) {
if (request_len > sizeof(scmd->cmnd)) {
ret = -EINVAL;
goto out_free_req;
}
scmd->cmd_len = cmd->request_len;
scmd->cmd_len = request_len;
scmd->allowed = SG_DEFAULT_RETRIES;

if (copy_from_user(scmd->cmnd, uptr64(cmd->request), cmd->request_len)) {
if (copy_from_user(scmd->cmnd, uptr64(request), request_len)) {
ret = -EFAULT;
goto out_free_req;
}
Expand All @@ -154,21 +166,27 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc
goto out_free_req;
}

pdu->response_addr = cmd->response;
scmd->sense_len = cmd->max_response_len ?
min(cmd->max_response_len, SCSI_SENSE_BUFFERSIZE) : SCSI_SENSE_BUFFERSIZE;
pdu->response_addr = response;
scmd->sense_len = max_response_len ?
min(max_response_len, SCSI_SENSE_BUFFERSIZE) : SCSI_SENSE_BUFFERSIZE;

if (cmd->dout_xfer_len || cmd->din_xfer_len) {
ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags, gfp_mask);
if (dout_xfer_len || din_xfer_len) {
bool is_write = dout_xfer_len > 0;
u64 buf_addr = is_write ? dout_xferp : din_xferp;
unsigned long buf_len = is_write ? dout_xfer_len : din_xfer_len;

ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags,
gfp_mask, is_write, buf_addr,
buf_len);
if (ret)
goto out_free_req;
pdu->bio = req->bio;
} else {
pdu->bio = NULL;
}

req->timeout = cmd->timeout_ms ?
msecs_to_jiffies(cmd->timeout_ms) : BLK_DEFAULT_SG_TIMEOUT;
req->timeout = timeout_ms ?
msecs_to_jiffies(timeout_ms) : BLK_DEFAULT_SG_TIMEOUT;

req->end_io = scsi_bsg_uring_cmd_done;
req->end_io_data = ioucmd;
Expand Down
Loading