]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - block/bsg-lib.c
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux.git] / block / bsg-lib.c
index 1921298563429a8165838e6c9dad6f0e9e6cb28d..005e2b75d775317ff2546e3574ea35894b1b3319 100644 (file)
@@ -51,11 +51,40 @@ static int bsg_transport_fill_hdr(struct request *rq, struct sg_io_v4 *hdr,
                fmode_t mode)
 {
        struct bsg_job *job = blk_mq_rq_to_pdu(rq);
+       int ret;
 
        job->request_len = 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)
@@ -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 */
        hdr->dout_resid = 0;
 
-       if (rq->next_rq) {
+       if (job->bidi_rq) {
                unsigned int rsp_len = job->reply_payload.payload_len;
 
                if (WARN_ON(job->reply_payload_rcv_len > rsp_len))
@@ -111,6 +140,11 @@ static void bsg_transport_free_rq(struct request *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);
 }
 
@@ -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)
 {
-       struct request *rsp = req->next_rq;
        struct bsg_job *job = blk_mq_rq_to_pdu(req);
        int ret;
 
@@ -211,8 +244,8 @@ static bool bsg_prepare_job(struct device *dev, struct request *req)
                if (ret)
                        goto failjob_rls_job;
        }
-       if (rsp && rsp->bio) {
-               ret = bsg_map_buffer(&job->reply_payload, rsp);
+       if (job->bidi_rq) {
+               ret = bsg_map_buffer(&job->reply_payload, job->bidi_rq);
                if (ret)
                        goto failjob_rls_rqst_payload;
        }
@@ -369,7 +402,6 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
        }
 
        q->queuedata = dev;
-       blk_queue_flag_set(QUEUE_FLAG_BIDI, q);
        blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
 
        ret = bsg_register_queue(q, dev, name, &bsg_transport_ops);