xen: Implement getgeo for Xen virtual block device.
[sfrench/cifs-2.6.git] / drivers / block / xen-blkfront.c
index 6746c29181f81493a00639a8117d3e5b7e7d82e4..9c6f3f99208d073ad9cbfd3ff61e69a0e3dc0a02 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
+#include <linux/hdreg.h>
 #include <linux/module.h>
 
 #include <xen/xenbus.h>
@@ -135,6 +136,22 @@ static void blkif_restart_queue_callback(void *arg)
        schedule_work(&info->work);
 }
 
+int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
+{
+       /* We don't have real geometry info, but let's at least return
+          values consistent with the size of the device */
+       sector_t nsect = get_capacity(bd->bd_disk);
+       sector_t cylinders = nsect;
+
+       hg->heads = 0xff;
+       hg->sectors = 0x3f;
+       sector_div(cylinders, hg->heads * hg->sectors);
+       hg->cylinders = cylinders;
+       if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
+               hg->cylinders = 0xffff;
+       return 0;
+}
+
 /*
  * blkif_queue_request
  *
@@ -150,9 +167,8 @@ static int blkif_queue_request(struct request *req)
        struct blkfront_info *info = req->rq_disk->private_data;
        unsigned long buffer_mfn;
        struct blkif_request *ring_req;
-       struct bio *bio;
+       struct req_iterator iter;
        struct bio_vec *bvec;
-       int idx;
        unsigned long id;
        unsigned int fsect, lsect;
        int ref;
@@ -186,34 +202,31 @@ static int blkif_queue_request(struct request *req)
                ring_req->operation = BLKIF_OP_WRITE_BARRIER;
 
        ring_req->nr_segments = 0;
-       rq_for_each_bio (bio, req) {
-               bio_for_each_segment (bvec, bio, idx) {
-                       BUG_ON(ring_req->nr_segments
-                              == BLKIF_MAX_SEGMENTS_PER_REQUEST);
-                       buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
-                       fsect = bvec->bv_offset >> 9;
-                       lsect = fsect + (bvec->bv_len >> 9) - 1;
-                       /* install a grant reference. */
-                       ref = gnttab_claim_grant_reference(&gref_head);
-                       BUG_ON(ref == -ENOSPC);
-
-                       gnttab_grant_foreign_access_ref(
+       rq_for_each_segment(bvec, req, iter) {
+               BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+               buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+               fsect = bvec->bv_offset >> 9;
+               lsect = fsect + (bvec->bv_len >> 9) - 1;
+               /* install a grant reference. */
+               ref = gnttab_claim_grant_reference(&gref_head);
+               BUG_ON(ref == -ENOSPC);
+
+               gnttab_grant_foreign_access_ref(
                                ref,
                                info->xbdev->otherend_id,
                                buffer_mfn,
                                rq_data_dir(req) );
 
-                       info->shadow[id].frame[ring_req->nr_segments] =
+               info->shadow[id].frame[ring_req->nr_segments] =
                                mfn_to_pfn(buffer_mfn);
 
-                       ring_req->seg[ring_req->nr_segments] =
+               ring_req->seg[ring_req->nr_segments] =
                                (struct blkif_request_segment) {
                                        .gref       = ref,
                                        .first_sect = fsect,
                                        .last_sect  = lsect };
 
-                       ring_req->nr_segments++;
-               }
+               ring_req->nr_segments++;
        }
 
        info->ring.req_prod_pvt++;
@@ -241,7 +254,7 @@ static inline void flush_requests(struct blkfront_info *info)
  * do_blkif_request
  *  read a block; request is in a request queue
  */
-static void do_blkif_request(request_queue_t *rq)
+static void do_blkif_request(struct request_queue *rq)
 {
        struct blkfront_info *info = NULL;
        struct request *req;
@@ -287,7 +300,7 @@ wait:
 
 static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 {
-       request_queue_t *rq;
+       struct request_queue *rq;
 
        rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
        if (rq == NULL)
@@ -456,7 +469,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
        RING_IDX i, rp;
        unsigned long flags;
        struct blkfront_info *info = (struct blkfront_info *)dev_id;
-       int uptodate;
+       int error;
 
        spin_lock_irqsave(&blkif_io_lock, flags);
 
@@ -481,13 +494,13 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
                add_id_to_freelist(info, id);
 
-               uptodate = (bret->status == BLKIF_RSP_OKAY);
+               error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
                switch (bret->operation) {
                case BLKIF_OP_WRITE_BARRIER:
                        if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
                                printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
                                       info->gd->disk_name);
-                               uptodate = -EOPNOTSUPP;
+                               error = -EOPNOTSUPP;
                                info->feature_barrier = 0;
                                xlvbd_barrier(info);
                        }
@@ -498,10 +511,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
                                        "request: %x\n", bret->status);
 
-                       ret = end_that_request_first(req, uptodate,
-                               req->hard_nr_sectors);
+                       ret = __blk_end_request(req, error, blk_rq_bytes(req));
                        BUG_ON(ret);
-                       end_that_request_last(req, uptodate);
                        break;
                default:
                        BUG();
@@ -943,6 +954,7 @@ static struct block_device_operations xlvbd_block_fops =
        .owner = THIS_MODULE,
        .open = blkif_open,
        .release = blkif_release,
+       .getgeo = blkif_getgeo,
 };