]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/block/sunvdc.c
Merge tag 'for-linus-20170812' of git://git.infradead.org/linux-mtd
[karo-tx-linux.git] / drivers / block / sunvdc.c
index 6b16ead1da5871abcef5b2233733f281158596a8..ad9749463d4fa9a382afa7f24587bbbe3a2efcc9 100644 (file)
@@ -875,6 +875,56 @@ static void print_version(void)
                printk(KERN_INFO "%s", version);
 }
 
+struct vdc_check_port_data {
+       int     dev_no;
+       char    *type;
+};
+
+static int vdc_device_probed(struct device *dev, void *arg)
+{
+       struct vio_dev *vdev = to_vio_dev(dev);
+       struct vdc_check_port_data *port_data;
+
+       port_data = (struct vdc_check_port_data *)arg;
+
+       if ((vdev->dev_no == port_data->dev_no) &&
+           (!(strcmp((char *)&vdev->type, port_data->type))) &&
+               dev_get_drvdata(dev)) {
+               /* This device has already been configured
+                * by vdc_port_probe()
+                */
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+/* Determine whether the VIO device is part of an mpgroup
+ * by locating all the virtual-device-port nodes associated
+ * with the parent virtual-device node for the VIO device
+ * and checking whether any of these nodes are vdc-ports
+ * which have already been configured.
+ *
+ * Returns true if this device is part of an mpgroup and has
+ * already been probed.
+ */
+static bool vdc_port_mpgroup_check(struct vio_dev *vdev)
+{
+       struct vdc_check_port_data port_data;
+       struct device *dev;
+
+       port_data.dev_no = vdev->dev_no;
+       port_data.type = (char *)&vdev->type;
+
+       dev = device_find_child(vdev->dev.parent, &port_data,
+                               vdc_device_probed);
+
+       if (dev)
+               return true;
+
+       return false;
+}
+
 static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
        struct mdesc_handle *hp;
@@ -893,6 +943,14 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                goto err_out_release_mdesc;
        }
 
+       /* Check if this device is part of an mpgroup */
+       if (vdc_port_mpgroup_check(vdev)) {
+               printk(KERN_WARNING
+                       "VIO: Ignoring extra vdisk port %s",
+                       dev_name(&vdev->dev));
+               goto err_out_release_mdesc;
+       }
+
        port = kzalloc(sizeof(*port), GFP_KERNEL);
        err = -ENOMEM;
        if (!port) {
@@ -943,6 +1001,9 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        if (err)
                goto err_out_free_tx_ring;
 
+       /* Note that the device driver_data is used to determine
+        * whether the port has been probed.
+        */
        dev_set_drvdata(&vdev->dev, port);
 
        mdesc_release(hp);