Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[sfrench/cifs-2.6.git] / drivers / block / viodasd.c
index af3969a9c96301d3ab515c44b1554c472ddcd4e3..41ca721d2523fec5987e02db1e9e7a26f35f60bb 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/scatterlist.h>
 
 #include <asm/uaccess.h>
 #include <asm/vio.h>
@@ -74,53 +75,9 @@ enum {
 static DEFINE_SPINLOCK(viodasd_spinlock);
 
 #define VIOMAXREQ              16
-#define VIOMAXBLOCKDMA         12
 
 #define DEVICE_NO(cell)        ((struct viodasd_device *)(cell) - &viodasd_devices[0])
 
-struct open_data {
-       u64     disk_size;
-       u16     max_disk;
-       u16     cylinders;
-       u16     tracks;
-       u16     sectors;
-       u16     bytes_per_sector;
-};
-
-struct rw_data {
-       u64     offset;
-       struct {
-               u32     token;
-               u32     reserved;
-               u64     len;
-       } dma_info[VIOMAXBLOCKDMA];
-};
-
-struct vioblocklpevent {
-       struct HvLpEvent        event;
-       u32                     reserved;
-       u16                     version;
-       u16                     sub_result;
-       u16                     disk;
-       u16                     flags;
-       union {
-               struct open_data        open_data;
-               struct rw_data          rw_data;
-               u64                     changed;
-       } u;
-};
-
-#define vioblockflags_ro   0x0001
-
-enum vioblocksubtype {
-       vioblockopen = 0x0001,
-       vioblockclose = 0x0002,
-       vioblockread = 0x0003,
-       vioblockwrite = 0x0004,
-       vioblockflush = 0x0005,
-       vioblockcheck = 0x0007
-};
-
 struct viodasd_waitevent {
        struct completion       com;
        int                     rc;
@@ -272,13 +229,10 @@ static struct block_device_operations viodasd_fops = {
 /*
  * End a request
  */
-static void viodasd_end_request(struct request *req, int uptodate,
+static void viodasd_end_request(struct request *req, int error,
                int num_sectors)
 {
-       if (end_that_request_first(req, uptodate, num_sectors))
-               return;
-       add_disk_randomness(req->rq_disk);
-       end_that_request_last(req, uptodate);
+       __blk_end_request(req, error, num_sectors << 9);
 }
 
 /*
@@ -314,6 +268,7 @@ static int send_request(struct request *req)
         d = req->rq_disk->private_data;
 
        /* Now build the scatter-gather list */
+       sg_init_table(sg, VIOMAXBLOCKDMA);
        nsg = blk_rq_map_sg(req->q, req, sg);
        nsg = dma_map_sg(d->dev, sg, nsg, direction);
 
@@ -416,12 +371,12 @@ static void do_viodasd_request(struct request_queue *q)
                blkdev_dequeue_request(req);
                /* check that request contains a valid command */
                if (!blk_fs_request(req)) {
-                       viodasd_end_request(req, 0, req->hard_nr_sectors);
+                       viodasd_end_request(req, -EIO, req->hard_nr_sectors);
                        continue;
                }
                /* Try sending the request */
                if (send_request(req) != 0)
-                       viodasd_end_request(req, 0, req->hard_nr_sectors);
+                       viodasd_end_request(req, -EIO, req->hard_nr_sectors);
        }
 }
 
@@ -429,7 +384,7 @@ static void do_viodasd_request(struct request_queue *q)
  * Probe a single disk and fill in the viodasd_device structure
  * for it.
  */
-static void probe_disk(struct viodasd_device *d)
+static int probe_disk(struct viodasd_device *d)
 {
        HvLpEvent_Rc hvrc;
        struct viodasd_waitevent we;
@@ -453,14 +408,14 @@ retry:
                        0, 0, 0);
        if (hvrc != 0) {
                printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc);
-               return;
+               return 0;
        }
 
        wait_for_completion(&we.com);
 
        if (we.rc != 0) {
                if (flags != 0)
-                       return;
+                       return 0;
                /* try again with read only flag set */
                flags = vioblockflags_ro;
                goto retry;
@@ -490,15 +445,32 @@ retry:
        if (hvrc != 0) {
                printk(VIOD_KERN_WARNING
                       "bad rc sending event to OS/400 %d\n", (int)hvrc);
-               return;
+               return 0;
+       }
+
+       if (d->dev == NULL) {
+               /* this is when we reprobe for new disks */
+               if (vio_create_viodasd(dev_no) == NULL) {
+                       printk(VIOD_KERN_WARNING
+                               "cannot allocate virtual device for disk %d\n",
+                               dev_no);
+                       return 0;
+               }
+               /*
+                * The vio_create_viodasd will have recursed into this
+                * routine with d->dev set to the new vio device and
+                * will finish the setup of the disk below.
+                */
+               return 1;
        }
+
        /* create the request queue for the disk */
        spin_lock_init(&d->q_lock);
        q = blk_init_queue(do_viodasd_request, &d->q_lock);
        if (q == NULL) {
                printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n",
                                dev_no);
-               return;
+               return 0;
        }
        g = alloc_disk(1 << PARTITION_SHIFT);
        if (g == NULL) {
@@ -506,7 +478,7 @@ retry:
                                "cannot allocate disk structure for disk %d\n",
                                dev_no);
                blk_cleanup_queue(q);
-               return;
+               return 0;
        }
 
        d->disk = g;
@@ -538,6 +510,7 @@ retry:
 
        /* register us in the global list */
        add_disk(g);
+       return 1;
 }
 
 /* returns the total number of scatterlist elements converted */
@@ -555,8 +528,7 @@ static int block_event_to_scatterlist(const struct vioblocklpevent *bevent,
                numsg = VIOMAXBLOCKDMA;
 
        *total_len = 0;
-       memset(sg, 0, sizeof(sg[0]) * VIOMAXBLOCKDMA);
-
+       sg_init_table(sg, VIOMAXBLOCKDMA);
        for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) {
                sg_dma_address(&sg[i]) = rw_data->dma_info[i].token;
                sg_dma_len(&sg[i]) = rw_data->dma_info[i].len;
@@ -615,7 +587,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
        num_req_outstanding--;
        spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
 
-       error = event->xRc != HvLpEvent_Rc_Good;
+       error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO;
        if (error) {
                const struct vio_error_entry *err;
                err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
@@ -625,7 +597,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
        }
        qlock = req->q->queue_lock;
        spin_lock_irqsave(qlock, irq_flags);
-       viodasd_end_request(req, !error, num_sect);
+       viodasd_end_request(req, error, num_sect);
        spin_unlock_irqrestore(qlock, irq_flags);
 
        /* Finally, try to get more requests off of this device's queue */
@@ -718,8 +690,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
 
        d->dev = &vdev->dev;
-       probe_disk(d);
-       if (d->disk == NULL)
+       if (!probe_disk(d))
                return -ENODEV;
        return 0;
 }