Commit 972248e9 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Martin K. Petersen

scsi: bsg-lib: handle bidi requests without block layer help

We can just stash away the second request in struct bsg_job instead of
using the block layer req->next_rq field, allowing for the eventual removal
of the latter.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent ccf3209f
...@@ -51,11 +51,40 @@ static int bsg_transport_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, ...@@ -51,11 +51,40 @@ static int bsg_transport_fill_hdr(struct request *rq, struct sg_io_v4 *hdr,
fmode_t mode) fmode_t mode)
{ {
struct bsg_job *job = blk_mq_rq_to_pdu(rq); struct bsg_job *job = blk_mq_rq_to_pdu(rq);
int ret;
job->request_len = hdr->request_len; job->request_len = hdr->request_len;
job->request = memdup_user(uptr64(hdr->request), hdr->request_len); job->request = memdup_user(uptr64(hdr->request), hdr->request_len);
if (IS_ERR(job->request))
return PTR_ERR(job->request);
if (hdr->dout_xfer_len && hdr->din_xfer_len) {
job->bidi_rq = blk_get_request(rq->q, REQ_OP_SCSI_IN, 0);
if (IS_ERR(job->bidi_rq)) {
ret = PTR_ERR(job->bidi_rq);
goto out;
}
ret = blk_rq_map_user(rq->q, job->bidi_rq, NULL,
uptr64(hdr->din_xferp), hdr->din_xfer_len,
GFP_KERNEL);
if (ret)
goto out_free_bidi_rq;
job->bidi_bio = job->bidi_rq->bio;
} else {
job->bidi_rq = NULL;
job->bidi_bio = NULL;
}
return PTR_ERR_OR_ZERO(job->request); return 0;
out_free_bidi_rq:
if (job->bidi_rq)
blk_put_request(job->bidi_rq);
out:
kfree(job->request);
return ret;
} }
static int bsg_transport_complete_rq(struct request *rq, struct sg_io_v4 *hdr) static int bsg_transport_complete_rq(struct request *rq, struct sg_io_v4 *hdr)
...@@ -93,7 +122,7 @@ static int bsg_transport_complete_rq(struct request *rq, struct sg_io_v4 *hdr) ...@@ -93,7 +122,7 @@ static int bsg_transport_complete_rq(struct request *rq, struct sg_io_v4 *hdr)
/* we assume all request payload was transferred, residual == 0 */ /* we assume all request payload was transferred, residual == 0 */
hdr->dout_resid = 0; hdr->dout_resid = 0;
if (rq->next_rq) { if (job->bidi_rq) {
unsigned int rsp_len = job->reply_payload.payload_len; unsigned int rsp_len = job->reply_payload.payload_len;
if (WARN_ON(job->reply_payload_rcv_len > rsp_len)) if (WARN_ON(job->reply_payload_rcv_len > rsp_len))
...@@ -111,6 +140,11 @@ static void bsg_transport_free_rq(struct request *rq) ...@@ -111,6 +140,11 @@ static void bsg_transport_free_rq(struct request *rq)
{ {
struct bsg_job *job = blk_mq_rq_to_pdu(rq); struct bsg_job *job = blk_mq_rq_to_pdu(rq);
if (job->bidi_rq) {
blk_rq_unmap_user(job->bidi_bio);
blk_put_request(job->bidi_rq);
}
kfree(job->request); kfree(job->request);
} }
...@@ -200,7 +234,6 @@ static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req) ...@@ -200,7 +234,6 @@ static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req)
*/ */
static bool bsg_prepare_job(struct device *dev, struct request *req) static bool bsg_prepare_job(struct device *dev, struct request *req)
{ {
struct request *rsp = req->next_rq;
struct bsg_job *job = blk_mq_rq_to_pdu(req); struct bsg_job *job = blk_mq_rq_to_pdu(req);
int ret; int ret;
...@@ -211,8 +244,8 @@ static bool bsg_prepare_job(struct device *dev, struct request *req) ...@@ -211,8 +244,8 @@ static bool bsg_prepare_job(struct device *dev, struct request *req)
if (ret) if (ret)
goto failjob_rls_job; goto failjob_rls_job;
} }
if (rsp && rsp->bio) { if (job->bidi_rq) {
ret = bsg_map_buffer(&job->reply_payload, rsp); ret = bsg_map_buffer(&job->reply_payload, job->bidi_rq);
if (ret) if (ret)
goto failjob_rls_rqst_payload; goto failjob_rls_rqst_payload;
} }
...@@ -369,7 +402,6 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name, ...@@ -369,7 +402,6 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
} }
q->queuedata = dev; q->queuedata = dev;
blk_queue_flag_set(QUEUE_FLAG_BIDI, q);
blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
ret = bsg_register_queue(q, dev, name, &bsg_transport_ops); ret = bsg_register_queue(q, dev, name, &bsg_transport_ops);
......
...@@ -74,6 +74,11 @@ static int bsg_scsi_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, ...@@ -74,6 +74,11 @@ static int bsg_scsi_fill_hdr(struct request *rq, struct sg_io_v4 *hdr,
{ {
struct scsi_request *sreq = scsi_req(rq); struct scsi_request *sreq = scsi_req(rq);
if (hdr->dout_xfer_len && hdr->din_xfer_len) {
pr_warn_once("BIDI support in bsg has been removed.\n");
return -EOPNOTSUPP;
}
sreq->cmd_len = hdr->request_len; sreq->cmd_len = hdr->request_len;
if (sreq->cmd_len > BLK_MAX_CDB) { if (sreq->cmd_len > BLK_MAX_CDB) {
sreq->cmd = kzalloc(sreq->cmd_len, GFP_KERNEL); sreq->cmd = kzalloc(sreq->cmd_len, GFP_KERNEL);
...@@ -114,14 +119,10 @@ static int bsg_scsi_complete_rq(struct request *rq, struct sg_io_v4 *hdr) ...@@ -114,14 +119,10 @@ static int bsg_scsi_complete_rq(struct request *rq, struct sg_io_v4 *hdr)
hdr->response_len = len; hdr->response_len = len;
} }
if (rq->next_rq) { if (rq_data_dir(rq) == READ)
hdr->dout_resid = sreq->resid_len;
hdr->din_resid = scsi_req(rq->next_rq)->resid_len;
} else if (rq_data_dir(rq) == READ) {
hdr->din_resid = sreq->resid_len; hdr->din_resid = sreq->resid_len;
} else { else
hdr->dout_resid = sreq->resid_len; hdr->dout_resid = sreq->resid_len;
}
return ret; return ret;
} }
...@@ -140,8 +141,8 @@ static const struct bsg_ops bsg_scsi_ops = { ...@@ -140,8 +141,8 @@ static const struct bsg_ops bsg_scsi_ops = {
static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
{ {
struct request *rq, *next_rq = NULL; struct request *rq;
struct bio *bio, *bidi_bio = NULL; struct bio *bio;
struct sg_io_v4 hdr; struct sg_io_v4 hdr;
int ret; int ret;
...@@ -164,7 +165,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) ...@@ -164,7 +165,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
ret = q->bsg_dev.ops->fill_hdr(rq, &hdr, mode); ret = q->bsg_dev.ops->fill_hdr(rq, &hdr, mode);
if (ret) if (ret)
goto out; return ret;
rq->timeout = msecs_to_jiffies(hdr.timeout); rq->timeout = msecs_to_jiffies(hdr.timeout);
if (!rq->timeout) if (!rq->timeout)
...@@ -174,29 +175,6 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) ...@@ -174,29 +175,6 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
if (rq->timeout < BLK_MIN_SG_TIMEOUT) if (rq->timeout < BLK_MIN_SG_TIMEOUT)
rq->timeout = BLK_MIN_SG_TIMEOUT; rq->timeout = BLK_MIN_SG_TIMEOUT;
if (hdr.dout_xfer_len && hdr.din_xfer_len) {
if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) {
ret = -EOPNOTSUPP;
goto out;
}
pr_warn_once(
"BIDI support in bsg has been deprecated and might be removed. "
"Please report your use case to linux-scsi@vger.kernel.org\n");
next_rq = blk_get_request(q, REQ_OP_SCSI_IN, 0);
if (IS_ERR(next_rq)) {
ret = PTR_ERR(next_rq);
goto out;
}
rq->next_rq = next_rq;
ret = blk_rq_map_user(q, next_rq, NULL, uptr64(hdr.din_xferp),
hdr.din_xfer_len, GFP_KERNEL);
if (ret)
goto out_free_nextrq;
}
if (hdr.dout_xfer_len) { if (hdr.dout_xfer_len) {
ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr.dout_xferp), ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr.dout_xferp),
hdr.dout_xfer_len, GFP_KERNEL); hdr.dout_xfer_len, GFP_KERNEL);
...@@ -206,38 +184,20 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) ...@@ -206,38 +184,20 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
} }
if (ret) if (ret)
goto out_unmap_nextrq; goto out_free_rq;
bio = rq->bio; bio = rq->bio;
if (rq->next_rq)
bidi_bio = rq->next_rq->bio;
blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL)); blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr); ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr);
if (rq->next_rq) {
blk_rq_unmap_user(bidi_bio);
blk_put_request(rq->next_rq);
}
blk_rq_unmap_user(bio); blk_rq_unmap_user(bio);
out_free_rq:
rq->q->bsg_dev.ops->free_rq(rq); rq->q->bsg_dev.ops->free_rq(rq);
blk_put_request(rq); blk_put_request(rq);
if (!ret && copy_to_user(uarg, &hdr, sizeof(hdr)))
if (copy_to_user(uarg, &hdr, sizeof(hdr)))
return -EFAULT; return -EFAULT;
return ret; return ret;
out_unmap_nextrq:
if (rq->next_rq)
blk_rq_unmap_user(rq->next_rq->bio);
out_free_nextrq:
if (rq->next_rq)
blk_put_request(rq->next_rq);
out:
q->bsg_dev.ops->free_rq(rq);
blk_put_request(rq);
return ret;
} }
static struct bsg_device *bsg_alloc_device(void) static struct bsg_device *bsg_alloc_device(void)
......
...@@ -213,7 +213,6 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) ...@@ -213,7 +213,6 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
to_sas_host_attrs(shost)->q = q; to_sas_host_attrs(shost)->q = q;
} }
blk_queue_flag_set(QUEUE_FLAG_BIDI, q);
return 0; return 0;
} }
......
...@@ -69,6 +69,10 @@ struct bsg_job { ...@@ -69,6 +69,10 @@ struct bsg_job {
int result; int result;
unsigned int reply_payload_rcv_len; unsigned int reply_payload_rcv_len;
/* BIDI support */
struct request *bidi_rq;
struct bio *bidi_bio;
void *dd_data; /* Used for driver-specific storage */ void *dd_data; /* Used for driver-specific storage */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment