Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7a610f7 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

s390/ccwgroup: exploit ccwdev_by_dev_id



Instead of finding devices via driver_find_device use the bus_find_device
wrapper get_ccwdev_by_dev_id. This allows us to get rid of the ccw_driver
argument of ccwgroup_create_dev and thus simplify the interface.

Reviewed-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent f2962dae
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -66,8 +66,8 @@ struct ccwgroup_driver {
extern int  ccwgroup_driver_register   (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
int ccwgroup_create_dev(struct device *root, unsigned int creator_id,
			struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv,
			int num_devices, const char *buf);
			struct ccwgroup_driver *gdrv, int num_devices,
			const char *buf);
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
				struct ccw_driver *cdrv, int num_devices,
				const char *buf);
+30 −39
Original line number Diff line number Diff line
@@ -15,10 +15,13 @@
#include <linux/ctype.h>
#include <linux/dcache.h>

#include <asm/cio.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>

#define CCW_BUS_ID_SIZE		20
#include "device.h"

#define CCW_BUS_ID_SIZE		10

/* In Linux 2.4, we had a channel device layer called "chandev"
 * that did all sorts of obscure stuff for networking devices.
@@ -254,9 +257,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
	return 0;
}

static int __get_next_bus_id(const char **buf, char *bus_id)
static int __get_next_id(const char **buf, struct ccw_dev_id *id)
{
	int rc, len;
	unsigned int cssid, ssid, devno;
	int ret = 0, len;
	char *start, *end;

	start = (char *)*buf;
@@ -271,50 +275,42 @@ static int __get_next_bus_id(const char **buf, char *bus_id)
		len = end - start + 1;
		end++;
	}
	if (len < CCW_BUS_ID_SIZE) {
		strlcpy(bus_id, start, len);
		rc = 0;
	if (len <= CCW_BUS_ID_SIZE) {
		if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3)
			ret = -EINVAL;
	} else
		rc = -EINVAL;
	*buf = end;
	return rc;
}

static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE])
{
	int cssid, ssid, devno;
		ret = -EINVAL;

	/* Must be of form %x.%x.%04x */
	if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
		return 0;
	return 1;
	if (!ret) {
		id->ssid = ssid;
		id->devno = devno;
	}
	*buf = end;
	return ret;
}

/**
 * ccwgroup_create_dev() - create and register a ccw group device
 * @parent: parent device for the new device
 * @creator_id: identifier of creating driver
 * @cdrv: ccw driver of slave devices
 * @gdrv: driver for the new group device
 * @num_devices: number of slave devices
 * @buf: buffer containing comma separated bus ids of slave devices
 *
 * Create and register a new ccw group device as a child of @parent. Slave
 * devices are obtained from the list of bus ids given in @buf and must all
 * belong to @cdrv.
 * devices are obtained from the list of bus ids given in @buf.
 * Returns:
 *  %0 on success and an error code on failure.
 * Context:
 *  non-atomic
 */
int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
			struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv,
			int num_devices, const char *buf)
			struct ccwgroup_driver *gdrv, int num_devices,
			const char *buf)
{
	struct ccwgroup_device *gdev;
	struct ccw_dev_id dev_id;
	int rc, i;
	char tmp_bus_id[CCW_BUS_ID_SIZE];
	const char *curr_buf;

	gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
		       GFP_KERNEL);
@@ -334,22 +330,18 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
	gdev->dev.release = ccwgroup_release;
	device_initialize(&gdev->dev);

	curr_buf = buf;
	for (i = 0; i < num_devices && curr_buf; i++) {
		rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
	for (i = 0; i < num_devices && buf; i++) {
		rc = __get_next_id(&buf, &dev_id);
		if (rc != 0)
			goto error;
		if (!__is_valid_bus_id(tmp_bus_id)) {
			rc = -EINVAL;
			goto error;
		}
		gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
		gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id);
		/*
		 * All devices have to be of the same type in
		 * order to be grouped.
		 */
		if (!gdev->cdev[i]
		    || gdev->cdev[i]->id.driver_info !=
		if (!gdev->cdev[i] || !gdev->cdev[i]->drv ||
		    gdev->cdev[i]->drv != gdev->cdev[0]->drv ||
		    gdev->cdev[i]->id.driver_info !=
		    gdev->cdev[0]->id.driver_info) {
			rc = -EINVAL;
			goto error;
@@ -365,12 +357,12 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
		spin_unlock_irq(gdev->cdev[i]->ccwlock);
	}
	/* Check for sufficient number of bus ids. */
	if (i < num_devices && !curr_buf) {
	if (i < num_devices) {
		rc = -EINVAL;
		goto error;
	}
	/* Check for trailing stuff. */
	if (i == num_devices && strlen(curr_buf) > 0) {
	if (i == num_devices && strlen(buf) > 0) {
		rc = -EINVAL;
		goto error;
	}
@@ -430,8 +422,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
				struct ccw_driver *cdrv, int num_devices,
				const char *buf)
{
	return ccwgroup_create_dev(root, creator_id, cdrv, NULL,
				   num_devices, buf);
	return ccwgroup_create_dev(root, creator_id, NULL, num_devices, buf);
}
EXPORT_SYMBOL(ccwgroup_create_from_string);

+12 −1
Original line number Diff line number Diff line
@@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data)
	return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
}

static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
/**
 * get_ccwdev_by_dev_id() - obtain device from a ccw device id
 * @dev_id: id of the device to be searched
 *
 * This function searches all devices attached to the ccw bus for a device
 * matching @dev_id.
 * Returns:
 *  If a device is found its reference count is increased and returned;
 *  else %NULL is returned.
 */
struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
{
	struct device *dev;

@@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)

	return dev ? to_ccwdev(dev) : NULL;
}
EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id);

static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
{
+1 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *);
void ccw_device_schedule_sch_unregister(struct ccw_device *);
int ccw_purge_blacklisted(void);
void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo);
struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id);

/* Function prototypes for device status and basic sense stuff. */
void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);