Skip to content

Commit

Permalink
ccwgroup: Unify parsing for group attribute.
Browse files Browse the repository at this point in the history
Instead of having each driver for ccwgroup slave device parsing the
input itself and calling ccwgroup_create(), introduce a new function
ccwgroup_create_from_string() and handle parsing inside the ccwgroup
core.

Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
  • Loading branch information
Ursula Braun authored and Jeff Garzik committed Apr 29, 2008
1 parent 8bbf844 commit 022b660
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 64 deletions.
96 changes: 75 additions & 21 deletions drivers/s390/cio/ccwgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}

static int __get_next_bus_id(const char **buf, char *bus_id)
{
int rc, len;
char *start, *end;

start = (char *)*buf;
end = strchr(start, ',');
if (!end) {
/* Last entry. Strip trailing newline, if applicable. */
end = strchr(start, '\n');
if (end)
*end = '\0';
len = strlen(start) + 1;
} else {
len = end - start + 1;
end++;
}
if (len < BUS_ID_SIZE) {
strlcpy(bus_id, start, len);
rc = 0;
} else
rc = -EINVAL;
*buf = end;
return rc;
}

static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
{
int cssid, ssid, devno;

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

/**
* ccwgroup_create() - create and register a ccw group device
* ccwgroup_create_from_string() - create and register a ccw group device
* @root: parent device for the new device
* @creator_id: identifier of creating driver
* @cdrv: ccw driver of slave devices
* @argc: number of slave devices
* @argv: bus ids of slave devices
* @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 @root. Slave
* devices are obtained from the list of bus ids given in @argv[] and must all
* devices are obtained from the list of bus ids given in @buf and must all
* belong to @cdrv.
* Returns:
* %0 on success and an error code on failure.
* Context:
* non-atomic
*/
int ccwgroup_create(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int argc, char *argv[])
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int num_devices,
const char *buf)
{
struct ccwgroup_device *gdev;
int i;
int rc;
int rc, i;
char tmp_bus_id[BUS_ID_SIZE];
const char *curr_buf;

if (argc > 256) /* disallow dumb users */
return -EINVAL;

gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
GFP_KERNEL);
if (!gdev)
return -ENOMEM;

atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
for (i = 0; i < argc; i++) {
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);

/* all devices have to be of the same type in
* order to be grouped */
curr_buf = buf;
for (i = 0; i < num_devices && curr_buf; i++) {
rc = __get_next_bus_id(&curr_buf, tmp_bus_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);
/*
* All devices have to be of the same type in
* order to be grouped.
*/
if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
Expand All @@ -204,9 +249,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
}
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
}

/* Check for sufficient number of bus ids. */
if (i < num_devices && !curr_buf) {
rc = -EINVAL;
goto error;
}
/* Check for trailing stuff. */
if (i == num_devices && strlen(curr_buf) > 0) {
rc = -EINVAL;
goto error;
}
gdev->creator_id = creator_id;
gdev->count = argc;
gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = root;
gdev->dev.release = ccwgroup_release;
Expand Down Expand Up @@ -234,7 +288,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error:
for (i = 0; i < argc; i++)
for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) {
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
Expand All @@ -244,6 +298,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
put_device(&gdev->dev);
return rc;
}
EXPORT_SYMBOL(ccwgroup_create_from_string);

static int __init
init_ccwgroup (void)
Expand Down Expand Up @@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister);
EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
20 changes: 2 additions & 18 deletions drivers/s390/net/cu3088.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
{
const char *start, *end;
char bus_ids[2][BUS_ID_SIZE], *argv[2];
int i;
int ret;
struct ccwgroup_driver *cdrv;

cdrv = to_ccwgroupdrv(drv);
if (!cdrv)
return -EINVAL;
start = buf;
for (i=0; i<2; i++) {
static const char delim[] = {',', '\n'};
int len;

if (!(end = strchr(start, delim[i])))
return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
strlcpy (bus_ids[i], start, len);
argv[i] = bus_ids[i];
start = end + 1;
}

ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
&cu3088_driver, 2, argv);
ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
&cu3088_driver, 2, buf);

return (ret == 0) ? count : ret;
}
Expand Down
23 changes: 2 additions & 21 deletions drivers/s390/net/qeth_core_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3827,27 +3827,8 @@ static struct ccw_driver qeth_ccw_driver = {
static int qeth_core_driver_group(const char *buf, struct device *root_dev,
unsigned long driver_id)
{
const char *start, *end;
char bus_ids[3][BUS_ID_SIZE], *argv[3];
int i;

start = buf;
for (i = 0; i < 3; i++) {
static const char delim[] = { ',', ',', '\n' };
int len;

end = strchr(start, delim[i]);
if (!end)
return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
strncpy(bus_ids[i], start, len);
bus_ids[i][len] = '\0';
start = end + 1;
argv[i] = bus_ids[i];
}

return (ccwgroup_create(root_dev, driver_id,
&qeth_ccw_driver, 3, argv));
return ccwgroup_create_from_string(root_dev, driver_id,
&qeth_ccw_driver, 3, buf);
}

int qeth_core_hardsetup_card(struct qeth_card *card)
Expand Down
7 changes: 3 additions & 4 deletions include/asm-s390/ccwgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ struct ccwgroup_driver {

extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
extern int ccwgroup_create (struct device *root,
unsigned int creator_id,
struct ccw_driver *gdrv,
int argc, char *argv[]);
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int num_devices,
const char *buf);

extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);
Expand Down

0 comments on commit 022b660

Please sign in to comment.