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