X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fblock%2Fviodasd.c;h=f63e07bd9f9c4e3b23f20c626c95e260451f1639;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=fdac6e3663e6b409e4f3c4ab7e56df9ea20bb562;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index fdac6e366..f63e07bd9 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -45,10 +45,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include 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);