Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / block / viodasd.c
index fdac6e3..f63e07b 100644 (file)
 
 #include <asm/uaccess.h>
 #include <asm/vio.h>
-#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/HvLpEvent.h>
-#include <asm/iSeries/HvLpConfig.h>
-#include <asm/iSeries/vio.h>
+#include <asm/iseries/hv_types.h>
+#include <asm/iseries/hv_lp_event.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/vio.h>
 
 MODULE_DESCRIPTION("iSeries Virtual DASD");
 MODULE_AUTHOR("Dave Boutcher");
@@ -68,11 +68,11 @@ MODULE_LICENSE("GPL");
 
 enum {
        PARTITION_SHIFT = 3,
-       MAX_DISKNO = 32,
+       MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
        MAX_DISK_NAME = sizeof(((struct gendisk *)0)->disk_name)
 };
 
-static spinlock_t      viodasd_spinlock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(viodasd_spinlock);
 
 #define VIOMAXREQ              16
 #define VIOMAXBLOCKDMA         12
@@ -168,6 +168,7 @@ struct viodasd_device {
        int             read_only;
        spinlock_t      q_lock;
        struct gendisk  *disk;
+       struct device   *dev;
 } viodasd_devices[MAX_DISKNO];
 
 /*
@@ -246,45 +247,17 @@ static int viodasd_release(struct inode *ino, struct file *fil)
 
 /* External ioctl entry point.
  */
-static int viodasd_ioctl(struct inode *ino, struct file *fil,
-                        unsigned int cmd, unsigned long arg)
+static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       int err;
-       unsigned char sectors;
-       unsigned char heads;
-       unsigned short cylinders;
-       struct hd_geometry *geo;
-       struct gendisk *gendisk;
-       struct viodasd_device *d;
+       struct gendisk *disk = bdev->bd_disk;
+       struct viodasd_device *d = disk->private_data;
 
-       switch (cmd) {
-       case HDIO_GETGEO:
-               geo = (struct hd_geometry *)arg;
-               if (geo == NULL)
-                       return -EINVAL;
-               err = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
-               if (err)
-                       return err;
-               gendisk = ino->i_bdev->bd_disk;
-               d = gendisk->private_data;
-               sectors = d->sectors;
-               if (sectors == 0)
-                       sectors = 32;
-               heads = d->tracks;
-               if (heads == 0)
-                       heads = 64;
-               cylinders = d->cylinders;
-               if (cylinders == 0)
-                       cylinders = get_capacity(gendisk) / (sectors * heads);
-               if (__put_user(sectors, &geo->sectors) ||
-                   __put_user(heads, &geo->heads) ||
-                   __put_user(cylinders, &geo->cylinders) ||
-                   __put_user(get_start_sect(ino->i_bdev), &geo->start))
-                       return -EFAULT;
-               return 0;
-       }
+       geo->sectors = d->sectors ? d->sectors : 0;
+       geo->heads = d->tracks ? d->tracks  : 64;
+       geo->cylinders = d->cylinders ? d->cylinders :
+               get_capacity(disk) / (geo->cylinders * geo->heads);
 
-       return -EINVAL;
+       return 0;
 }
 
 /*
@@ -294,7 +267,7 @@ static struct block_device_operations viodasd_fops = {
        .owner = THIS_MODULE,
        .open = viodasd_open,
        .release = viodasd_release,
-       .ioctl = viodasd_ioctl,
+       .getgeo = viodasd_getgeo,
 };
 
 /*
@@ -306,7 +279,7 @@ static void viodasd_end_request(struct request *req, int uptodate,
        if (end_that_request_first(req, uptodate, num_sectors))
                return;
        add_disk_randomness(req->rq_disk);
-       end_that_request_last(req);
+       end_that_request_last(req, uptodate);
 }
 
 /*
@@ -320,6 +293,7 @@ static int send_request(struct request *req)
        u16 viocmd;
        HvLpEvent_Rc hvrc;
        struct vioblocklpevent *bevent;
+       struct HvLpEvent *hev;
        struct scatterlist sg[VIOMAXBLOCKDMA];
        int sgindex;
        int statindex;
@@ -342,7 +316,7 @@ static int send_request(struct request *req)
 
        /* Now build the scatter-gather list */
        nsg = blk_rq_map_sg(req->q, req, sg);
-       nsg = dma_map_sg(iSeries_vio_dev, sg, nsg, direction);
+       nsg = dma_map_sg(d->dev, sg, nsg, direction);
 
        spin_lock_irqsave(&viodasd_spinlock, flags);
        num_req_outstanding++;
@@ -374,22 +348,19 @@ static int send_request(struct request *req)
                 * token so we can match the response up later
                 */
                memset(bevent, 0, sizeof(struct vioblocklpevent));
-               bevent->event.xFlags.xValid = 1;
-               bevent->event.xFlags.xFunction = HvLpEvent_Function_Int;
-               bevent->event.xFlags.xAckInd = HvLpEvent_AckInd_DoAck;
-               bevent->event.xFlags.xAckType = HvLpEvent_AckType_ImmediateAck;
-               bevent->event.xType = HvLpEvent_Type_VirtualIo;
-               bevent->event.xSubtype = viocmd;
-               bevent->event.xSourceLp = HvLpConfig_getLpIndex();
-               bevent->event.xTargetLp = viopath_hostLp;
-               bevent->event.xSizeMinus1 =
+               hev = &bevent->event;
+               hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK |
+                       HV_LP_EVENT_INT;
+               hev->xType = HvLpEvent_Type_VirtualIo;
+               hev->xSubtype = viocmd;
+               hev->xSourceLp = HvLpConfig_getLpIndex();
+               hev->xTargetLp = viopath_hostLp;
+               hev->xSizeMinus1 =
                        offsetof(struct vioblocklpevent, u.rw_data.dma_info) +
                        (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1;
-               bevent->event.xSourceInstanceId =
-                       viopath_sourceinst(viopath_hostLp);
-               bevent->event.xTargetInstanceId =
-                       viopath_targetinst(viopath_hostLp);
-               bevent->event.xCorrelationToken = (u64)req;
+               hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp);
+               hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp);
+               hev->xCorrelationToken = (u64)req;
                bevent->version = VIOVERSION;
                bevent->disk = DEVICE_NO(d);
                bevent->u.rw_data.offset = start;
@@ -422,7 +393,7 @@ static int send_request(struct request *req)
 error_ret:
        num_req_outstanding--;
        spin_unlock_irqrestore(&viodasd_spinlock, flags);
-       dma_unmap_sg(iSeries_vio_dev, sg, nsg, direction);
+       dma_unmap_sg(d->dev, sg, nsg, direction);
        return -1;
 }
 
@@ -557,6 +528,7 @@ retry:
        g->fops = &viodasd_fops;
        g->queue = q;
        g->private_data = d;
+       g->driverfs_dev = d->dev;
        set_capacity(g, d->size >> 9);
 
        printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) "
@@ -623,7 +595,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
        struct scatterlist sg[VIOMAXBLOCKDMA];
        struct HvLpEvent *event = &bevent->event;
        unsigned long irq_flags;
-       int device_no;
+       struct viodasd_device *d;
        int error;
        spinlock_t *qlock;
 
@@ -633,7 +605,10 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
                pci_direction = DMA_FROM_DEVICE;
        else
                pci_direction = DMA_TO_DEVICE;
-       dma_unmap_sg(iSeries_vio_dev, sg, num_sg, pci_direction);
+       req = (struct request *)bevent->event.xCorrelationToken;
+       d = req->rq_disk->private_data;
+
+       dma_unmap_sg(d->dev, sg, num_sg, pci_direction);
 
        /*
         * Since this is running in interrupt mode, we need to make sure
@@ -643,9 +618,6 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
        num_req_outstanding--;
        spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
 
-       req = (struct request *)bevent->event.xCorrelationToken;
-       device_no = DEVICE_NO(req->rq_disk->private_data);
-
        error = event->xRc != HvLpEvent_Rc_Good;
        if (error) {
                const struct vio_error_entry *err;
@@ -660,7 +632,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
        spin_unlock_irqrestore(qlock, irq_flags);
 
        /* Finally, try to get more requests off of this device's queue */
-       viodasd_restart_all_queues_starting_from(device_no);
+       viodasd_restart_all_queues_starting_from(DEVICE_NO(d));
 
        return 0;
 }
@@ -675,10 +647,10 @@ static void handle_block_event(struct HvLpEvent *event)
                /* Notification that a partition went away! */
                return;
        /* First, we should NEVER get an int here...only acks */
-       if (event->xFlags.xFunction == HvLpEvent_Function_Int) {
+       if (hvlpevent_is_int(event)) {
                printk(VIOD_KERN_WARNING
                       "Yikes! got an int in viodasd event handler!\n");
-               if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) {
+               if (hvlpevent_need_ack(event)) {
                        event->xRc = HvLpEvent_Rc_InvalidSubtype;
                        HvCallEvent_ackLpEvent(event);
                }
@@ -721,7 +693,7 @@ static void handle_block_event(struct HvLpEvent *event)
 
        default:
                printk(VIOD_KERN_WARNING "invalid subtype!");
-               if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) {
+               if (hvlpevent_need_ack(event)) {
                        event->xRc = HvLpEvent_Rc_InvalidSubtype;
                        HvCallEvent_ackLpEvent(event);
                }
@@ -742,10 +714,52 @@ static ssize_t probe_disks(struct device_driver *drv, const char *buf,
        }
        return count;
 }
-static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks)
+static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks);
+
+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)
+               return -ENODEV;
+       return 0;
+}
+
+static int viodasd_remove(struct vio_dev *vdev)
+{
+       struct viodasd_device *d;
+
+       d = &viodasd_devices[vdev->unit_address];
+       if (d->disk) {
+               del_gendisk(d->disk);
+               blk_cleanup_queue(d->disk->queue);
+               put_disk(d->disk);
+               d->disk = NULL;
+       }
+       d->dev = NULL;
+       return 0;
+}
+
+/**
+ * viodasd_device_table: Used by vio.c to match devices that we
+ * support.
+ */
+static struct vio_device_id viodasd_device_table[] __devinitdata = {
+       { "viodasd", "" },
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, viodasd_device_table);
 
 static struct vio_driver viodasd_driver = {
-       .name = "viodasd"
+       .id_table = viodasd_device_table,
+       .probe = viodasd_probe,
+       .remove = viodasd_remove,
+       .driver = {
+               .name = "viodasd",
+               .owner = THIS_MODULE,
+       }
 };
 
 /*
@@ -754,7 +768,7 @@ static struct vio_driver viodasd_driver = {
  */
 static int __init viodasd_init(void)
 {
-       int i;
+       int rc;
 
        /* Try to open to our host lp */
        if (viopath_hostLp == HvLpIndexInvalid)
@@ -788,33 +802,17 @@ static int __init viodasd_init(void)
        /* Initialize our request handler */
        vio_setHandler(viomajorsubtype_blockio, handle_block_event);
 
-       for (i = 0; i < MAX_DISKNO; i++)
-               probe_disk(&viodasd_devices[i]);
-
-       vio_register_driver(&viodasd_driver);   /* FIX ME - error checking */
-       driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
-
-       return 0;
+       rc = vio_register_driver(&viodasd_driver);
+       if (rc == 0)
+               driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
+       return rc;
 }
 module_init(viodasd_init);
 
 void viodasd_exit(void)
 {
-       int i;
-       struct viodasd_device *d;
-
        driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
        vio_unregister_driver(&viodasd_driver);
-
-        for (i = 0; i < MAX_DISKNO; i++) {
-               d = &viodasd_devices[i];
-               if (d->disk) {
-                       del_gendisk(d->disk);
-                       put_disk(d->disk);
-                       blk_cleanup_queue(d->disk->queue);
-                       d->disk = NULL;
-               }
-       }
        vio_clearHandler(viomajorsubtype_blockio);
        unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
        viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);