[POWERPC] iSeries: Move detection of virtual tapes
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Oct 2007 04:58:31 +0000 (14:58 +1000)
committerPaul Mackerras <paulus@samba.org>
Thu, 11 Oct 2007 10:40:47 +0000 (20:40 +1000)
Now we will only have entries in the device tree for the actual existing
devices (including their OS/400 properties).  This way viotape.c gets
all the information about the devices from the device tree.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/iseries/dt.c
arch/powerpc/platforms/iseries/vio.c
drivers/char/viotape.c
include/asm-powerpc/iseries/vio.h

index 84fcee15eb2522ff6c52ca0595b26ac6fc579b34..2e4ad6b34506ed73e9dc73e0cfba139afd578e1d 100644 (file)
@@ -73,7 +73,6 @@ static char __initdata device_type_memory[] = "memory";
 static char __initdata device_type_serial[] = "serial";
 static char __initdata device_type_network[] = "network";
 static char __initdata device_type_block[] = "block";
-static char __initdata device_type_byte[] = "byte";
 static char __initdata device_type_pci[] = "pci";
 static char __initdata device_type_vdevice[] = "vdevice";
 static char __initdata device_type_vscsi[] = "vscsi";
@@ -380,12 +379,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt)
        for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
                dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
                                "IBM,iSeries-viodasd", 1);
-       reg += HVMAXARCHITECTEDVIRTUALDISKS;
-       reg += HVMAXARCHITECTEDVIRTUALCDROMS;
-
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
-               dt_do_vdevice(dt, "viotape", reg, i, device_type_byte,
-                               "IBM,iSeries-viotape", 1);
 
        dt_end_node(dt);
 }
index f61a97441c3d3b2e945286b0c8ec15123dba6b1e..a4cc990a26a0ac02eda8e7377fff866cda546dfb 100644 (file)
 #define FIRST_VIOTAPE  (FIRST_VIOCD + NUM_VIOCDS)
 #define NUM_VIOTAPES   HVMAXARCHITECTEDVIRTUALTAPES
 
+struct vio_waitevent {
+       struct completion       com;
+       int                     rc;
+       u16                     sub_result;
+};
+
+struct vio_resource {
+       char    rsrcname[10];
+       char    type[4];
+       char    model[3];
+};
+
 static struct property * __init new_property(const char *name, int length,
                const void *value)
 {
@@ -123,22 +135,10 @@ static int __init add_raw_property(struct device_node *np, const char *name,
        return 1;
 }
 
-struct viocd_waitevent {
-       struct completion       com;
-       int                     rc;
-       u16                     sub_result;
-};
-
-struct cdrom_info {
-       char    rsrcname[10];
-       char    type[4];
-       char    model[3];
-};
-
 static void __init handle_cd_event(struct HvLpEvent *event)
 {
        struct viocdlpevent *bevent;
-       struct viocd_waitevent *pwe;
+       struct vio_waitevent *pwe;
 
        if (!event)
                /* Notification that a partition went away! */
@@ -158,7 +158,7 @@ static void __init handle_cd_event(struct HvLpEvent *event)
 
        switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
        case viocdgetinfo:
-               pwe = (struct viocd_waitevent *)event->xCorrelationToken;
+               pwe = (struct vio_waitevent *)event->xCorrelationToken;
                pwe->rc = event->xRc;
                pwe->sub_result = bevent->sub_result;
                complete(&pwe->com);
@@ -179,8 +179,8 @@ static void __init get_viocd_info(struct device_node *vio_root)
 {
        HvLpEvent_Rc hvrc;
        u32 unit;
-       struct viocd_waitevent we;
-       struct cdrom_info *unitinfo;
+       struct vio_waitevent we;
+       struct vio_resource *unitinfo;
        dma_addr_t unitinfo_dmaaddr;
        int ret;
 
@@ -286,6 +286,122 @@ static void __init get_viocd_info(struct device_node *vio_root)
        viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
 }
 
+/* Handle interrupt events for tape */
+static void __init handle_tape_event(struct HvLpEvent *event)
+{
+       struct vio_waitevent *we;
+       struct viotapelpevent *tevent = (struct viotapelpevent *)event;
+
+       if (event == NULL)
+               /* Notification that a partition went away! */
+               return;
+
+       we = (struct vio_waitevent *)event->xCorrelationToken;
+       switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
+       case viotapegetinfo:
+               we->rc = tevent->sub_type_result;
+               complete(&we->com);
+               break;
+       default:
+               printk(KERN_WARNING "handle_tape_event: weird ack\n");
+       }
+}
+
+static void __init get_viotape_info(struct device_node *vio_root)
+{
+       HvLpEvent_Rc hvrc;
+       u32 unit;
+       struct vio_resource *unitinfo;
+       dma_addr_t unitinfo_dmaaddr;
+       size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES;
+       struct vio_waitevent we;
+       int ret;
+
+       ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2);
+       if (ret) {
+               printk(KERN_WARNING "get_viotape_info: "
+                       "error on viopath_open to hostlp %d\n", ret);
+               return;
+       }
+
+       vio_setHandler(viomajorsubtype_tape, handle_tape_event);
+
+       unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC);
+       if (!unitinfo)
+               goto clear_handler;
+
+       memset(unitinfo, 0, len);
+
+       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+                       HvLpEvent_Type_VirtualIo,
+                       viomajorsubtype_tape | viotapegetinfo,
+                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+                       viopath_sourceinst(viopath_hostLp),
+                       viopath_targetinst(viopath_hostLp),
+                       (u64)(unsigned long)&we, VIOVERSION << 16,
+                       unitinfo_dmaaddr, len, 0, 0);
+       if (hvrc != HvLpEvent_Rc_Good) {
+               printk(KERN_WARNING "get_viotape_info: hv error on op %d\n",
+                               (int)hvrc);
+               goto hv_free;
+       }
+
+       wait_for_completion(&we.com);
+
+       for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
+                       unitinfo[unit].rsrcname[0]; unit++) {
+               struct device_node *np;
+               char name[64];
+               u32 reg = FIRST_VIOTAPE + unit;
+
+               snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg);
+               np = new_node(name, vio_root);
+               if (!np)
+                       goto hv_free;
+               if (!add_string_property(np, "name", "viotape") ||
+                       !add_string_property(np, "device_type", "byte") ||
+                       !add_string_property(np, "compatible",
+                               "IBM,iSeries-viotape") ||
+                       !add_raw_property(np, "reg", sizeof(reg), &reg) ||
+                       !add_raw_property(np, "linux,unit_address",
+                               sizeof(unit), &unit) ||
+                       !add_raw_property(np, "linux,vio_rsrcname",
+                               sizeof(unitinfo[unit].rsrcname),
+                               unitinfo[unit].rsrcname) ||
+                       !add_raw_property(np, "linux,vio_type",
+                               sizeof(unitinfo[unit].type),
+                               unitinfo[unit].type) ||
+                       !add_raw_property(np, "linux,vio_model",
+                               sizeof(unitinfo[unit].model),
+                               unitinfo[unit].model))
+                       goto node_free;
+               np->name = of_get_property(np, "name", NULL);
+               np->type = of_get_property(np, "device_type", NULL);
+               of_attach_node(np);
+#ifdef CONFIG_PROC_DEVICETREE
+               if (vio_root->pde) {
+                       struct proc_dir_entry *ent;
+
+                       ent = proc_mkdir(strrchr(np->full_name, '/') + 1,
+                                       vio_root->pde);
+                       if (ent)
+                               proc_device_tree_add_node(np, ent);
+               }
+#endif
+               continue;
+
+ node_free:
+               free_node(np);
+               break;
+       }
+
+ hv_free:
+       iseries_hv_free(len, unitinfo, unitinfo_dmaaddr);
+ clear_handler:
+       vio_clearHandler(viomajorsubtype_tape);
+       viopath_close(viopath_hostLp, viomajorsubtype_tape, 2);
+}
+
 static int __init iseries_vio_init(void)
 {
        struct device_node *vio_root;
@@ -307,6 +423,7 @@ static int __init iseries_vio_init(void)
        }
 
        get_viocd_info(vio_root);
+       get_viotape_info(vio_root);
 
        return 0;
 
index 064c091952152861814d7295c6cc9e687352d2f8..f1d60f0cef8f860b3b402a680e98f71214e975d7 100644 (file)
@@ -92,47 +92,6 @@ struct viot_devinfo_struct {
 #define VIOTAPOP_SETPART       14
 #define VIOTAPOP_UNLOAD        15
 
-struct viotapelpevent {
-       struct HvLpEvent event;
-       u32 reserved;
-       u16 version;
-       u16 sub_type_result;
-       u16 tape;
-       u16 flags;
-       u32 token;
-       u64 len;
-       union {
-               struct {
-                       u32 tape_op;
-                       u32 count;
-               } op;
-               struct {
-                       u32 type;
-                       u32 resid;
-                       u32 dsreg;
-                       u32 gstat;
-                       u32 erreg;
-                       u32 file_no;
-                       u32 block_no;
-               } get_status;
-               struct {
-                       u32 block_no;
-               } get_pos;
-       } u;
-};
-
-enum viotapesubtype {
-       viotapeopen = 0x0001,
-       viotapeclose = 0x0002,
-       viotaperead = 0x0003,
-       viotapewrite = 0x0004,
-       viotapegetinfo = 0x0005,
-       viotapeop = 0x0006,
-       viotapegetpos = 0x0007,
-       viotapesetpos = 0x0008,
-       viotapegetstatus = 0x0009
-};
-
 enum viotaperc {
        viotape_InvalidRange = 0x0601,
        viotape_InvalidToken = 0x0602,
@@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = {
 #define VIOT_WRITING           2
 
 /* Our info on the tapes */
-struct tape_descr {
-       char rsrcname[10];
-       char type[4];
-       char model[3];
-};
-
-static struct tape_descr *viotape_unitinfo;
-static dma_addr_t viotape_unitinfo_token;
+static struct {
+       const char *rsrcname;
+       const char *type;
+       const char *model;
+} viotape_unitinfo[VIOTAPE_MAX_TAPE];
 
 static struct mtget viomtget[VIOTAPE_MAX_TAPE];
 
@@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
        return -err->errno;
 }
 
-/* Get info on all tapes from OS/400 */
-static int get_viotape_info(void)
-{
-       HvLpEvent_Rc hvrc;
-       int i;
-       size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE;
-       struct op_struct *op = get_op_struct();
-
-       if (op == NULL)
-               return -ENOMEM;
-
-       viotape_unitinfo = iseries_hv_alloc(len, &viotape_unitinfo_token,
-               GFP_ATOMIC);
-       if (viotape_unitinfo == NULL) {
-               free_op_struct(op);
-               return -ENOMEM;
-       }
-
-       memset(viotape_unitinfo, 0, len);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_tape | viotapegetinfo,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64) (unsigned long) op, VIOVERSION << 16,
-                       viotape_unitinfo_token, len, 0, 0);
-       if (hvrc != HvLpEvent_Rc_Good) {
-               printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-                               (int)hvrc);
-               free_op_struct(op);
-               return -EIO;
-       }
-
-       wait_for_completion(&op->com);
-
-       free_op_struct(op);
-
-       for (i = 0;
-            ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
-            i++)
-               viotape_numdev++;
-       return 0;
-}
-
-
 /* Write */
 static ssize_t viotap_write(struct file *file, const char *buf,
                size_t count, loff_t * ppos)
@@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event)
        tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
        op = (struct op_struct *)event->xCorrelationToken;
        switch (tapeminor) {
-       case viotapegetinfo:
        case viotapeopen:
        case viotapeclose:
                op->rc = tevent->sub_type_result;
@@ -942,11 +850,23 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
        int i = vdev->unit_address;
        int j;
+       struct device_node *node = vdev->dev.archdata.of_node;
 
-       if (i >= viotape_numdev)
+       if (i > VIOTAPE_MAX_TAPE)
+               return -ENODEV;
+       if (!node)
                return -ENODEV;
 
+       if (i >= viotape_numdev)
+               viotape_numdev = i + 1;
+
        tape_device[i] = &vdev->dev;
+       viotape_unitinfo[i].rsrcname = of_get_property(node,
+                                       "linux,vio_rsrcname", NULL);
+       viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
+                                       NULL);
+       viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
+                                       NULL);
 
        state[i].cur_part = 0;
        for (j = 0; j < MAX_PARTITIONS; ++j)
@@ -1044,11 +964,6 @@ int __init viotap_init(void)
                goto unreg_chrdev;
        }
 
-       if ((ret = get_viotape_info()) < 0) {
-               printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");
-               goto unreg_class;
-       }
-
        ret = vio_register_driver(&viotape_driver);
        if (ret)
                goto unreg_class;
@@ -1102,9 +1017,6 @@ static void __exit viotap_exit(void)
        vio_unregister_driver(&viotape_driver);
        class_destroy(tape_class);
        unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-       if (viotape_unitinfo)
-               iseries_hv_free(sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
-                               viotape_unitinfo, viotape_unitinfo_token);
        viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
        vio_clearHandler(viomajorsubtype_tape);
        clear_op_struct_pool();
index e5a405b8d4613dda99ac336b8a790bb44afce3ac..2555dfd6fac6d573b1310bacdae5e646563e77f2 100644 (file)
@@ -75,6 +75,47 @@ enum viocdsubtype {
        viocdcheck = 0x0007
 };
 
+struct viotapelpevent {
+       struct HvLpEvent event;
+       u32 reserved;
+       u16 version;
+       u16 sub_type_result;
+       u16 tape;
+       u16 flags;
+       u32 token;
+       u64 len;
+       union {
+               struct {
+                       u32 tape_op;
+                       u32 count;
+               } op;
+               struct {
+                       u32 type;
+                       u32 resid;
+                       u32 dsreg;
+                       u32 gstat;
+                       u32 erreg;
+                       u32 file_no;
+                       u32 block_no;
+               } get_status;
+               struct {
+                       u32 block_no;
+               } get_pos;
+       } u;
+};
+
+enum viotapesubtype {
+       viotapeopen = 0x0001,
+       viotapeclose = 0x0002,
+       viotaperead = 0x0003,
+       viotapewrite = 0x0004,
+       viotapegetinfo = 0x0005,
+       viotapeop = 0x0006,
+       viotapegetpos = 0x0007,
+       viotapesetpos = 0x0008,
+       viotapegetstatus = 0x0009
+};
+
 /*
  * Each subtype can register a handler to process their events.
  * The handler must have this interface.