#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
+#include <linux/scatterlist.h>
#include <asm/vio.h>
#include <asm/ldc.h>
struct vdc_port {
struct vio_driver_state vio;
- struct vdc *vp;
-
struct gendisk *disk;
struct vdc_completion *cmp;
u64 operations;
u32 vdisk_size;
u8 vdisk_type;
- u8 dev_no;
char disk_name[32];
struct vio_disk_geom geom;
struct vio_disk_vtoc label;
-
- struct list_head list;
};
static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
return container_of(vio, struct vdc_port, vio);
}
-struct vdc {
- /* Protects prot_list. */
- spinlock_t lock;
-
- struct vio_dev *dev;
-
- struct list_head port_list;
-};
-
/* Ordered from largest major to lowest */
static struct vio_version vdc_versions[] = {
{ .major = 1, .minor = 0 },
vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
}
-static void vdc_end_request(struct request *req, int uptodate, int num_sectors)
+static void vdc_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);
}
static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
rqe->req = NULL;
- vdc_end_request(req, !desc->status, desc->size >> 9);
+ vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9);
if (blk_queue_stopped(port->disk->queue))
blk_start_queue(port->disk->queue);
op = VD_OP_BWRITE;
}
+ sg_init_table(sg, port->ring_cookies);
nsg = blk_rq_map_sg(req->q, req, sg);
len = 0;
desc->req_id = port->req_id;
desc->operation = op;
if (port->vdisk_type == VD_DISK_TYPE_DISK) {
- desc->slice = 2;
+ desc->slice = 0xff;
} else {
desc->slice = 0;
}
return err;
}
-static void do_vdc_request(request_queue_t *q)
+static void do_vdc_request(struct request_queue *q)
{
while (1) {
struct request *req = elv_next_request(q);
blkdev_dequeue_request(req);
if (__send_request(req) < 0)
- vdc_end_request(req, 0, req->hard_nr_sectors);
+ vdc_end_request(req, -EIO, req->hard_nr_sectors);
}
}
blk_queue_max_phys_segments(q, port->ring_cookies);
blk_queue_max_sectors(q, port->max_xfer_size);
g->major = vdc_major;
- g->first_minor = port->dev_no << PARTITION_SHIFT;
+ g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
strcpy(g->disk_name, port->disk_name);
g->fops = &vdc_fops;
.handshake_complete = vdc_handshake_complete,
};
+static void __devinit print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
static int __devinit vdc_port_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
- struct mdesc_node *endp;
+ struct mdesc_handle *hp;
struct vdc_port *port;
- unsigned long flags;
- struct vdc *vp;
- const u64 *port_id;
int err;
- vp = dev_get_drvdata(vdev->dev.parent);
- if (!vp) {
- printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
- return -ENODEV;
- }
+ print_version();
- endp = vio_find_endpoint(vdev);
- if (!endp) {
- printk(KERN_ERR PFX "Port lacks channel-endpoint.\n");
- return -ENODEV;
- }
+ hp = mdesc_grab();
- port_id = md_get_property(vdev->mp, "id", NULL);
- if (!port_id) {
- printk(KERN_ERR PFX "Port lacks id property.\n");
- return -ENODEV;
- }
- if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
- printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
- return -ENODEV;
+ err = -ENODEV;
+ if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+ printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+ vdev->dev_no);
+ goto err_out_release_mdesc;
}
port = kzalloc(sizeof(*port), GFP_KERNEL);
+ err = -ENOMEM;
if (!port) {
printk(KERN_ERR PFX "Cannot allocate vdc_port.\n");
- return -ENOMEM;
+ goto err_out_release_mdesc;
}
- port->vp = vp;
- port->dev_no = *port_id;
-
- if (port->dev_no >= 26)
+ if (vdev->dev_no >= 26)
snprintf(port->disk_name, sizeof(port->disk_name),
VDCBLK_NAME "%c%c",
- 'a' + (port->dev_no / 26) - 1,
- 'a' + (port->dev_no % 26));
+ 'a' + ((int)vdev->dev_no / 26) - 1,
+ 'a' + ((int)vdev->dev_no % 26));
else
snprintf(port->disk_name, sizeof(port->disk_name),
- VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+ VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
- err = vio_driver_init(&port->vio, vdev, VDEV_DISK, endp,
+ err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
vdc_versions, ARRAY_SIZE(vdc_versions),
&vdc_vio_ops, port->disk_name);
if (err)
if (err)
goto err_out_free_tx_ring;
- INIT_LIST_HEAD(&port->list);
-
- spin_lock_irqsave(&vp->lock, flags);
- list_add(&port->list, &vp->port_list);
- spin_unlock_irqrestore(&vp->lock, flags);
-
dev_set_drvdata(&vdev->dev, port);
+ mdesc_release(hp);
+
return 0;
err_out_free_tx_ring:
err_out_free_port:
kfree(port);
+err_out_release_mdesc:
+ mdesc_release(hp);
return err;
}
},
{},
};
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
static struct vio_driver vdc_port_driver = {
.id_table = vdc_port_match,
}
};
-static int __devinit vdc_probe(struct vio_dev *vdev,
- const struct vio_device_id *id)
-{
- static int vdc_version_printed;
- struct vdc *vp;
-
- if (vdc_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-
- vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
- if (!vp)
- return -ENOMEM;
-
- spin_lock_init(&vp->lock);
- vp->dev = vdev;
- INIT_LIST_HEAD(&vp->port_list);
-
- dev_set_drvdata(&vdev->dev, vp);
-
- return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
- struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
- if (vp) {
- kfree(vp);
- dev_set_drvdata(&vdev->dev, NULL);
- }
- return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
- {
- .type = "block",
- },
- {},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
- .id_table = vdc_match,
- .probe = vdc_probe,
- .remove = vdc_remove,
- .driver = {
- .name = "vdc",
- .owner = THIS_MODULE,
- }
-};
-
static int __init vdc_init(void)
{
int err;
goto out_err;
vdc_major = err;
- err = vio_register_driver(&vdc_driver);
- if (err)
- goto out_unregister_blkdev;
err = vio_register_driver(&vdc_port_driver);
if (err)
- goto out_unregister_vdc;
+ goto out_unregister_blkdev;
return 0;
-out_unregister_vdc:
- vio_unregister_driver(&vdc_driver);
-
out_unregister_blkdev:
unregister_blkdev(vdc_major, VDCBLK_NAME);
vdc_major = 0;
static void __exit vdc_exit(void)
{
vio_unregister_driver(&vdc_port_driver);
- vio_unregister_driver(&vdc_driver);
unregister_blkdev(vdc_major, VDCBLK_NAME);
}