diff options
| -rw-r--r-- | drivers/block/sunvdc.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 6b16ead1da58..ad9749463d4f 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c | |||
| @@ -875,6 +875,56 @@ static void print_version(void) | |||
| 875 | printk(KERN_INFO "%s", version); | 875 | printk(KERN_INFO "%s", version); |
| 876 | } | 876 | } |
| 877 | 877 | ||
| 878 | struct vdc_check_port_data { | ||
| 879 | int dev_no; | ||
| 880 | char *type; | ||
| 881 | }; | ||
| 882 | |||
| 883 | static int vdc_device_probed(struct device *dev, void *arg) | ||
| 884 | { | ||
| 885 | struct vio_dev *vdev = to_vio_dev(dev); | ||
| 886 | struct vdc_check_port_data *port_data; | ||
| 887 | |||
| 888 | port_data = (struct vdc_check_port_data *)arg; | ||
| 889 | |||
| 890 | if ((vdev->dev_no == port_data->dev_no) && | ||
| 891 | (!(strcmp((char *)&vdev->type, port_data->type))) && | ||
| 892 | dev_get_drvdata(dev)) { | ||
| 893 | /* This device has already been configured | ||
| 894 | * by vdc_port_probe() | ||
| 895 | */ | ||
| 896 | return 1; | ||
| 897 | } else { | ||
| 898 | return 0; | ||
| 899 | } | ||
| 900 | } | ||
| 901 | |||
| 902 | /* Determine whether the VIO device is part of an mpgroup | ||
| 903 | * by locating all the virtual-device-port nodes associated | ||
| 904 | * with the parent virtual-device node for the VIO device | ||
| 905 | * and checking whether any of these nodes are vdc-ports | ||
| 906 | * which have already been configured. | ||
| 907 | * | ||
| 908 | * Returns true if this device is part of an mpgroup and has | ||
| 909 | * already been probed. | ||
| 910 | */ | ||
| 911 | static bool vdc_port_mpgroup_check(struct vio_dev *vdev) | ||
| 912 | { | ||
| 913 | struct vdc_check_port_data port_data; | ||
| 914 | struct device *dev; | ||
| 915 | |||
| 916 | port_data.dev_no = vdev->dev_no; | ||
| 917 | port_data.type = (char *)&vdev->type; | ||
| 918 | |||
| 919 | dev = device_find_child(vdev->dev.parent, &port_data, | ||
| 920 | vdc_device_probed); | ||
| 921 | |||
| 922 | if (dev) | ||
| 923 | return true; | ||
| 924 | |||
| 925 | return false; | ||
| 926 | } | ||
| 927 | |||
| 878 | static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) | 928 | static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) |
| 879 | { | 929 | { |
| 880 | struct mdesc_handle *hp; | 930 | struct mdesc_handle *hp; |
| @@ -893,6 +943,14 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
| 893 | goto err_out_release_mdesc; | 943 | goto err_out_release_mdesc; |
| 894 | } | 944 | } |
| 895 | 945 | ||
| 946 | /* Check if this device is part of an mpgroup */ | ||
| 947 | if (vdc_port_mpgroup_check(vdev)) { | ||
| 948 | printk(KERN_WARNING | ||
| 949 | "VIO: Ignoring extra vdisk port %s", | ||
| 950 | dev_name(&vdev->dev)); | ||
| 951 | goto err_out_release_mdesc; | ||
| 952 | } | ||
| 953 | |||
| 896 | port = kzalloc(sizeof(*port), GFP_KERNEL); | 954 | port = kzalloc(sizeof(*port), GFP_KERNEL); |
| 897 | err = -ENOMEM; | 955 | err = -ENOMEM; |
| 898 | if (!port) { | 956 | if (!port) { |
| @@ -943,6 +1001,9 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
| 943 | if (err) | 1001 | if (err) |
| 944 | goto err_out_free_tx_ring; | 1002 | goto err_out_free_tx_ring; |
| 945 | 1003 | ||
| 1004 | /* Note that the device driver_data is used to determine | ||
| 1005 | * whether the port has been probed. | ||
| 1006 | */ | ||
| 946 | dev_set_drvdata(&vdev->dev, port); | 1007 | dev_set_drvdata(&vdev->dev, port); |
| 947 | 1008 | ||
| 948 | mdesc_release(hp); | 1009 | mdesc_release(hp); |
