From: Stephen Rothwell <sfr@canb.auug.org.au>

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ppc64/kernel/vio.c             |    2 
 25-akpm/drivers/char/viotape.c              |  119 ++++++++++++++++++----------
 25-akpm/include/asm-ppc64/iSeries/HvTypes.h |    1 
 3 files changed, 80 insertions(+), 42 deletions(-)

diff -puN arch/ppc64/kernel/vio.c~ppc64-viotape-integration arch/ppc64/kernel/vio.c
--- 25/arch/ppc64/kernel/vio.c~ppc64-viotape-integration	2004-06-28 13:22:14.852517008 -0700
+++ 25-akpm/arch/ppc64/kernel/vio.c	2004-06-28 13:22:14.858516096 -0700
@@ -237,6 +237,8 @@ static void probe_bus_iseries(void)
 		vio_register_device_iseries("viodasd", i);
 	for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
 		vio_register_device_iseries("viocd", i);
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
+		vio_register_device_iseries("viotape", i);
 }
 #endif
 
diff -puN drivers/char/viotape.c~ppc64-viotape-integration drivers/char/viotape.c
--- 25/drivers/char/viotape.c~ppc64-viotape-integration	2004-06-28 13:22:14.853516856 -0700
+++ 25-akpm/drivers/char/viotape.c	2004-06-28 13:22:14.860515792 -0700
@@ -53,6 +53,7 @@
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
+#include <asm/vio.h>
 #include <asm/iSeries/vio.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallEvent.h>
@@ -216,7 +217,7 @@ static const struct vio_error_entry viot
 };
 
 /* Maximum number of tapes we support */
-#define VIOTAPE_MAX_TAPE	8
+#define VIOTAPE_MAX_TAPE	HVMAXARCHITECTEDVIRTUALTAPES
 #define MAX_PARTITIONS		4
 
 /* defines for current tape state */
@@ -238,6 +239,8 @@ static struct mtget viomtget[VIOTAPE_MAX
 
 static struct class_simple *tape_class;
 
+static struct device *tape_device[VIOTAPE_MAX_TAPE];
+
 /*
  * maintain the current state of each tape (and partition)
  * so that we know when to write EOF marks.
@@ -262,6 +265,7 @@ struct op_struct {
 	int			rc;
 	int			non_blocking;
 	struct completion	com;
+	struct device		*dev;
 	struct op_struct	*next;
 };
 
@@ -459,7 +463,8 @@ static ssize_t viotap_write(struct file 
 		down(&reqSem);
 
 	/* Allocate a DMA buffer */
-	op->buffer = dma_alloc_coherent(iSeries_vio_dev, count, &op->dmaaddr,
+	op->dev = tape_device[devi.devno];
+	op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
 			GFP_ATOMIC);
 
 	if (op->buffer == NULL) {
@@ -509,7 +514,7 @@ static ssize_t viotap_write(struct file 
 	}
 
 free_dma:
-	dma_free_coherent(iSeries_vio_dev, count, op->buffer, op->dmaaddr);
+	dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
 up_sem:
 	up(&reqSem);
 free_op:
@@ -550,7 +555,8 @@ static ssize_t viotap_read(struct file *
 	chg_state(devi.devno, VIOT_READING, file);
 
 	/* Allocate a DMA buffer */
-	op->buffer = dma_alloc_coherent(iSeries_vio_dev, count, &op->dmaaddr,
+	op->dev = tape_device[devi.devno];
+	op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
 			GFP_ATOMIC);
 	if (op->buffer == NULL) {
 		ret = -EFAULT;
@@ -588,7 +594,7 @@ static ssize_t viotap_read(struct file *
 	}
 
 free_dma:
-	dma_free_coherent(iSeries_vio_dev, count, op->buffer, op->dmaaddr);
+	dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
 up_sem:
 	up(&reqSem);
 free_op:
@@ -910,7 +916,7 @@ static void vioHandleTapeEvent(struct Hv
 		break;
 	case viotapewrite:
 		if (op->non_blocking) {
-			dma_free_coherent(iSeries_vio_dev, op->count,
+			dma_free_coherent(op->dev, op->count,
 					op->buffer, op->dmaaddr);
 			free_op_struct(op);
 			up(&reqSem);
@@ -936,12 +942,70 @@ static void vioHandleTapeEvent(struct Hv
 	}
 }
 
+static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
+{
+	char tapename[32];
+	int i = vdev->unit_address;
+	int j;
+
+	if (i >= viotape_numdev)
+		return -ENODEV;
+
+	tape_device[i] = &vdev->dev;
+
+	state[i].cur_part = 0;
+	for (j = 0; j < MAX_PARTITIONS; ++j)
+		state[i].part_stat_rwi[j] = VIOT_IDLE;
+	class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL,
+			"iseries!vt%d", i);
+	class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+			NULL, "iseries!nvt%d", i);
+	devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR,
+			"iseries/vt%d", i);
+	devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80),
+			S_IFCHR | S_IRUSR | S_IWUSR, "iseries/nvt%d", i);
+	sprintf(tapename, "iseries/vt%d", i);
+	state[i].dev_handle = devfs_register_tape(tapename);
+	printk(VIOTAPE_KERN_INFO "tape %s is iSeries "
+			"resource %10.10s type %4.4s, model %3.3s\n",
+			tapename, viotape_unitinfo[i].rsrcname,
+			viotape_unitinfo[i].type, viotape_unitinfo[i].model);
+	return 0;
+}
+
+static int viotape_remove(struct vio_dev *vdev)
+{
+	int i = vdev->unit_address;
+
+	devfs_remove("iseries/nvt%d", i);
+	devfs_remove("iseries/vt%d", i);
+	devfs_unregister_tape(state[i].dev_handle);
+	class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80));
+	class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i));
+	return 0;
+}
+
+/**
+ * viotape_device_table: Used by vio.c to match devices that we
+ * support.
+ */
+static struct vio_device_id viotape_device_table[] __devinitdata = {
+	{ "viotape", "" },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(vio, viotape_device_table);
+static struct vio_driver viotape_driver = {
+	.name = "viotape",
+	.id_table = viotape_device_table,
+	.probe = viotape_probe,
+	.remove = viotape_remove
+};
+
 
 int __init viotap_init(void)
 {
 	int ret;
-	char tapename[32];
-	int i;
 	struct proc_dir_entry *e;
 
 	op_struct_list = NULL;
@@ -993,31 +1057,9 @@ int __init viotap_init(void)
 		goto unreg_class;
 	}
 
-	for (i = 0; i < viotape_numdev; i++) {
-		int j;
-
-		state[i].cur_part = 0;
-		for (j = 0; j < MAX_PARTITIONS; ++j)
-			state[i].part_stat_rwi[j] = VIOT_IDLE;
-		class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i),
-				NULL, "iseries!vt%d", i);
-		class_simple_device_add(tape_class,
-				MKDEV(VIOTAPE_MAJOR, i | 0x80),
-				NULL, "iseries!nvt%d", i);
-		devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i),
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				"iseries/vt%d", i);
-		devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80),
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				"iseries/nvt%d", i);
-		sprintf(tapename, "iseries/vt%d", i);
-		state[i].dev_handle = devfs_register_tape(tapename);
-		printk(VIOTAPE_KERN_INFO "tape %s is iSeries "
-				"resource %10.10s type %4.4s, model %3.3s\n",
-				tapename, viotape_unitinfo[i].rsrcname,
-				viotape_unitinfo[i].type,
-				viotape_unitinfo[i].model);
-	}
+	ret = vio_register_driver(&viotape_driver);
+	if (ret)
+		goto unreg_class;
 
 	e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL);
 	if (e) {
@@ -1064,17 +1106,10 @@ static int chg_state(int index, unsigned
 /* Cleanup */
 static void __exit viotap_exit(void)
 {
-	int i, ret;
+	int ret;
 
 	remove_proc_entry("iSeries/viotape", NULL);
-
-	for (i = 0; i < viotape_numdev; ++i) {
-		devfs_remove("iseries/nvt%d", i);
-		devfs_remove("iseries/vt%d", i);
-		devfs_unregister_tape(state[i].dev_handle);
-		class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80));
-		class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i));
-	}
+	vio_unregister_driver(&viotape_driver);
 	class_simple_destroy(tape_class);
 	ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
 	if (ret < 0)
diff -puN include/asm-ppc64/iSeries/HvTypes.h~ppc64-viotape-integration include/asm-ppc64/iSeries/HvTypes.h
--- 25/include/asm-ppc64/iSeries/HvTypes.h~ppc64-viotape-integration	2004-06-28 13:22:14.855516552 -0700
+++ 25-akpm/include/asm-ppc64/iSeries/HvTypes.h	2004-06-28 13:22:14.861515640 -0700
@@ -68,6 +68,7 @@ typedef u8	HvAgentId;		// Hypervisor Dev
 #define HVMAXARCHITECTEDVIRTUALLANS 16
 #define HVMAXARCHITECTEDVIRTUALDISKS 32
 #define HVMAXARCHITECTEDVIRTUALCDROMS 8
+#define HVMAXARCHITECTEDVIRTUALTAPES 8
 #define HVCHUNKSIZE 256 * 1024
 #define HVPAGESIZE 4 * 1024
 #define HVLPMINMEGSPRIMARY 256
_