aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/ccwgroup.c96
1 files changed, 75 insertions, 21 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 03914fa81174..f38923e38e92 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
153 return 0; 153 return 0;
154} 154}
155 155
156static int __get_next_bus_id(const char **buf, char *bus_id)
157{
158 int rc, len;
159 char *start, *end;
160
161 start = (char *)*buf;
162 end = strchr(start, ',');
163 if (!end) {
164 /* Last entry. Strip trailing newline, if applicable. */
165 end = strchr(start, '\n');
166 if (end)
167 *end = '\0';
168 len = strlen(start) + 1;
169 } else {
170 len = end - start + 1;
171 end++;
172 }
173 if (len < BUS_ID_SIZE) {
174 strlcpy(bus_id, start, len);
175 rc = 0;
176 } else
177 rc = -EINVAL;
178 *buf = end;
179 return rc;
180}
181
182static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
183{
184 int cssid, ssid, devno;
185
186 /* Must be of form %x.%x.%04x */
187 if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
188 return 0;
189 return 1;
190}
191
156/** 192/**
157 * ccwgroup_create() - create and register a ccw group device 193 * ccwgroup_create_from_string() - create and register a ccw group device
158 * @root: parent device for the new device 194 * @root: parent device for the new device
159 * @creator_id: identifier of creating driver 195 * @creator_id: identifier of creating driver
160 * @cdrv: ccw driver of slave devices 196 * @cdrv: ccw driver of slave devices
161 * @argc: number of slave devices 197 * @num_devices: number of slave devices
162 * @argv: bus ids of slave devices 198 * @buf: buffer containing comma separated bus ids of slave devices
163 * 199 *
164 * Create and register a new ccw group device as a child of @root. Slave 200 * Create and register a new ccw group device as a child of @root. Slave
165 * devices are obtained from the list of bus ids given in @argv[] and must all 201 * devices are obtained from the list of bus ids given in @buf and must all
166 * belong to @cdrv. 202 * belong to @cdrv.
167 * Returns: 203 * Returns:
168 * %0 on success and an error code on failure. 204 * %0 on success and an error code on failure.
169 * Context: 205 * Context:
170 * non-atomic 206 * non-atomic
171 */ 207 */
172int ccwgroup_create(struct device *root, unsigned int creator_id, 208int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
173 struct ccw_driver *cdrv, int argc, char *argv[]) 209 struct ccw_driver *cdrv, int num_devices,
210 const char *buf)
174{ 211{
175 struct ccwgroup_device *gdev; 212 struct ccwgroup_device *gdev;
176 int i; 213 int rc, i;
177 int rc; 214 char tmp_bus_id[BUS_ID_SIZE];
215 const char *curr_buf;
178 216
179 if (argc > 256) /* disallow dumb users */ 217 gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
180 return -EINVAL; 218 GFP_KERNEL);
181
182 gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
183 if (!gdev) 219 if (!gdev)
184 return -ENOMEM; 220 return -ENOMEM;
185 221
186 atomic_set(&gdev->onoff, 0); 222 atomic_set(&gdev->onoff, 0);
187 mutex_init(&gdev->reg_mutex); 223 mutex_init(&gdev->reg_mutex);
188 mutex_lock(&gdev->reg_mutex); 224 mutex_lock(&gdev->reg_mutex);
189 for (i = 0; i < argc; i++) { 225 curr_buf = buf;
190 gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); 226 for (i = 0; i < num_devices && curr_buf; i++) {
191 227 rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
192 /* all devices have to be of the same type in 228 if (rc != 0)
193 * order to be grouped */ 229 goto error;
230 if (!__is_valid_bus_id(tmp_bus_id)) {
231 rc = -EINVAL;
232 goto error;
233 }
234 gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
235 /*
236 * All devices have to be of the same type in
237 * order to be grouped.
238 */
194 if (!gdev->cdev[i] 239 if (!gdev->cdev[i]
195 || gdev->cdev[i]->id.driver_info != 240 || gdev->cdev[i]->id.driver_info !=
196 gdev->cdev[0]->id.driver_info) { 241 gdev->cdev[0]->id.driver_info) {
@@ -204,9 +249,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
204 } 249 }
205 dev_set_drvdata(&gdev->cdev[i]->dev, gdev); 250 dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
206 } 251 }
207 252 /* Check for sufficient number of bus ids. */
253 if (i < num_devices && !curr_buf) {
254 rc = -EINVAL;
255 goto error;
256 }
257 /* Check for trailing stuff. */
258 if (i == num_devices && strlen(curr_buf) > 0) {
259 rc = -EINVAL;
260 goto error;
261 }
208 gdev->creator_id = creator_id; 262 gdev->creator_id = creator_id;
209 gdev->count = argc; 263 gdev->count = num_devices;
210 gdev->dev.bus = &ccwgroup_bus_type; 264 gdev->dev.bus = &ccwgroup_bus_type;
211 gdev->dev.parent = root; 265 gdev->dev.parent = root;
212 gdev->dev.release = ccwgroup_release; 266 gdev->dev.release = ccwgroup_release;
@@ -234,7 +288,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
234 device_remove_file(&gdev->dev, &dev_attr_ungroup); 288 device_remove_file(&gdev->dev, &dev_attr_ungroup);
235 device_unregister(&gdev->dev); 289 device_unregister(&gdev->dev);
236error: 290error:
237 for (i = 0; i < argc; i++) 291 for (i = 0; i < num_devices; i++)
238 if (gdev->cdev[i]) { 292 if (gdev->cdev[i]) {
239 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) 293 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
240 dev_set_drvdata(&gdev->cdev[i]->dev, NULL); 294 dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@@ -244,6 +298,7 @@ error:
244 put_device(&gdev->dev); 298 put_device(&gdev->dev);
245 return rc; 299 return rc;
246} 300}
301EXPORT_SYMBOL(ccwgroup_create_from_string);
247 302
248static int __init 303static int __init
249init_ccwgroup (void) 304init_ccwgroup (void)
@@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
519MODULE_LICENSE("GPL"); 574MODULE_LICENSE("GPL");
520EXPORT_SYMBOL(ccwgroup_driver_register); 575EXPORT_SYMBOL(ccwgroup_driver_register);
521EXPORT_SYMBOL(ccwgroup_driver_unregister); 576EXPORT_SYMBOL(ccwgroup_driver_unregister);
522EXPORT_SYMBOL(ccwgroup_create);
523EXPORT_SYMBOL(ccwgroup_probe_ccwdev); 577EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
524EXPORT_SYMBOL(ccwgroup_remove_ccwdev); 578EXPORT_SYMBOL(ccwgroup_remove_ccwdev);