xref: /openbmc/linux/drivers/s390/block/dcssblk.c (revision f15cbe6f1a4b4d9df59142fc8e4abb973302cf44)
1 /*
2  * dcssblk.c -- the S/390 block driver for dcss memory
3  *
4  * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer
5  */
6 
7 #include <linux/module.h>
8 #include <linux/moduleparam.h>
9 #include <linux/ctype.h>
10 #include <linux/errno.h>
11 #include <linux/init.h>
12 #include <linux/slab.h>
13 #include <linux/blkdev.h>
14 #include <asm/extmem.h>
15 #include <asm/io.h>
16 #include <linux/completion.h>
17 #include <linux/interrupt.h>
18 #include <asm/s390_rdev.h>
19 
20 //#define DCSSBLK_DEBUG		/* Debug messages on/off */
21 #define DCSSBLK_NAME "dcssblk"
22 #define DCSSBLK_MINORS_PER_DISK 1
23 #define DCSSBLK_PARM_LEN 400
24 
25 #ifdef DCSSBLK_DEBUG
26 #define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x)
27 #else
28 #define PRINT_DEBUG(x...) do {} while (0)
29 #endif
30 #define PRINT_INFO(x...)  printk(KERN_INFO DCSSBLK_NAME " info: " x)
31 #define PRINT_WARN(x...)  printk(KERN_WARNING DCSSBLK_NAME " warning: " x)
32 #define PRINT_ERR(x...)	  printk(KERN_ERR DCSSBLK_NAME " error: " x)
33 
34 
35 static int dcssblk_open(struct inode *inode, struct file *filp);
36 static int dcssblk_release(struct inode *inode, struct file *filp);
37 static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
38 static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
39 				 void **kaddr, unsigned long *pfn);
40 
41 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
42 
43 static int dcssblk_major;
44 static struct block_device_operations dcssblk_devops = {
45 	.owner   	= THIS_MODULE,
46 	.open    	= dcssblk_open,
47 	.release 	= dcssblk_release,
48 	.direct_access 	= dcssblk_direct_access,
49 };
50 
51 static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
52 				  size_t count);
53 static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
54 				  size_t count);
55 static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
56 				  size_t count);
57 static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
58 static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
59 				  size_t count);
60 static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
61 
62 static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
63 static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
64 static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show,
65 		   dcssblk_save_store);
66 static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show,
67 		   dcssblk_shared_store);
68 
69 static struct device *dcssblk_root_dev;
70 
71 struct dcssblk_dev_info {
72 	struct list_head lh;
73 	struct device dev;
74 	char segment_name[BUS_ID_SIZE];
75 	atomic_t use_count;
76 	struct gendisk *gd;
77 	unsigned long start;
78 	unsigned long end;
79 	int segment_type;
80 	unsigned char save_pending;
81 	unsigned char is_shared;
82 	struct request_queue *dcssblk_queue;
83 };
84 
85 static LIST_HEAD(dcssblk_devices);
86 static struct rw_semaphore dcssblk_devices_sem;
87 
88 /*
89  * release function for segment device.
90  */
91 static void
92 dcssblk_release_segment(struct device *dev)
93 {
94 	PRINT_DEBUG("segment release fn called for %s\n", dev->bus_id);
95 	kfree(container_of(dev, struct dcssblk_dev_info, dev));
96 	module_put(THIS_MODULE);
97 }
98 
99 /*
100  * get a minor number. needs to be called with
101  * down_write(&dcssblk_devices_sem) and the
102  * device needs to be enqueued before the semaphore is
103  * freed.
104  */
105 static int
106 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
107 {
108 	int minor, found;
109 	struct dcssblk_dev_info *entry;
110 
111 	if (dev_info == NULL)
112 		return -EINVAL;
113 	for (minor = 0; minor < (1<<MINORBITS); minor++) {
114 		found = 0;
115 		// test if minor available
116 		list_for_each_entry(entry, &dcssblk_devices, lh)
117 			if (minor == entry->gd->first_minor)
118 				found++;
119 		if (!found) break; // got unused minor
120 	}
121 	if (found)
122 		return -EBUSY;
123 	dev_info->gd->first_minor = minor;
124 	return 0;
125 }
126 
127 /*
128  * get the struct dcssblk_dev_info from dcssblk_devices
129  * for the given name.
130  * down_read(&dcssblk_devices_sem) must be held.
131  */
132 static struct dcssblk_dev_info *
133 dcssblk_get_device_by_name(char *name)
134 {
135 	struct dcssblk_dev_info *entry;
136 
137 	list_for_each_entry(entry, &dcssblk_devices, lh) {
138 		if (!strcmp(name, entry->segment_name)) {
139 			return entry;
140 		}
141 	}
142 	return NULL;
143 }
144 
145 static void dcssblk_unregister_callback(struct device *dev)
146 {
147 	device_unregister(dev);
148 	put_device(dev);
149 }
150 
151 /*
152  * device attribute for switching shared/nonshared (exclusive)
153  * operation (show + store)
154  */
155 static ssize_t
156 dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf)
157 {
158 	struct dcssblk_dev_info *dev_info;
159 
160 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
161 	return sprintf(buf, dev_info->is_shared ? "1\n" : "0\n");
162 }
163 
164 static ssize_t
165 dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
166 {
167 	struct dcssblk_dev_info *dev_info;
168 	int rc;
169 
170 	if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
171 		return -EINVAL;
172 	down_write(&dcssblk_devices_sem);
173 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
174 	if (atomic_read(&dev_info->use_count)) {
175 		PRINT_ERR("share: segment %s is busy!\n",
176 			  dev_info->segment_name);
177 		rc = -EBUSY;
178 		goto out;
179 	}
180 	if (inbuf[0] == '1') {
181 		// reload segment in shared mode
182 		rc = segment_modify_shared(dev_info->segment_name,
183 					   SEGMENT_SHARED);
184 		if (rc < 0) {
185 			BUG_ON(rc == -EINVAL);
186 			if (rc != -EAGAIN)
187 				goto removeseg;
188 		} else {
189 			dev_info->is_shared = 1;
190 			switch (dev_info->segment_type) {
191 				case SEG_TYPE_SR:
192 				case SEG_TYPE_ER:
193 				case SEG_TYPE_SC:
194 					set_disk_ro(dev_info->gd,1);
195 			}
196 		}
197 	} else if (inbuf[0] == '0') {
198 		// reload segment in exclusive mode
199 		if (dev_info->segment_type == SEG_TYPE_SC) {
200 			PRINT_ERR("Segment type SC (%s) cannot be loaded in "
201 				  "non-shared mode\n", dev_info->segment_name);
202 			rc = -EINVAL;
203 			goto out;
204 		}
205 		rc = segment_modify_shared(dev_info->segment_name,
206 					   SEGMENT_EXCLUSIVE);
207 		if (rc < 0) {
208 			BUG_ON(rc == -EINVAL);
209 			if (rc != -EAGAIN)
210 				goto removeseg;
211 		} else {
212 			dev_info->is_shared = 0;
213 			set_disk_ro(dev_info->gd, 0);
214 		}
215 	} else {
216 		rc = -EINVAL;
217 		goto out;
218 	}
219 	rc = count;
220 	goto out;
221 
222 removeseg:
223 	PRINT_ERR("Could not reload segment %s, removing it now!\n",
224 			dev_info->segment_name);
225 	list_del(&dev_info->lh);
226 
227 	del_gendisk(dev_info->gd);
228 	blk_cleanup_queue(dev_info->dcssblk_queue);
229 	dev_info->gd->queue = NULL;
230 	put_disk(dev_info->gd);
231 	rc = device_schedule_callback(dev, dcssblk_unregister_callback);
232 out:
233 	up_write(&dcssblk_devices_sem);
234 	return rc;
235 }
236 
237 /*
238  * device attribute for save operation on current copy
239  * of the segment. If the segment is busy, saving will
240  * become pending until it gets released, which can be
241  * undone by storing a non-true value to this entry.
242  * (show + store)
243  */
244 static ssize_t
245 dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf)
246 {
247 	struct dcssblk_dev_info *dev_info;
248 
249 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
250 	return sprintf(buf, dev_info->save_pending ? "1\n" : "0\n");
251 }
252 
253 static ssize_t
254 dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
255 {
256 	struct dcssblk_dev_info *dev_info;
257 
258 	if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
259 		return -EINVAL;
260 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
261 
262 	down_write(&dcssblk_devices_sem);
263 	if (inbuf[0] == '1') {
264 		if (atomic_read(&dev_info->use_count) == 0) {
265 			// device is idle => we save immediately
266 			PRINT_INFO("Saving segment %s\n",
267 				   dev_info->segment_name);
268 			segment_save(dev_info->segment_name);
269 		}  else {
270 			// device is busy => we save it when it becomes
271 			// idle in dcssblk_release
272 			PRINT_INFO("Segment %s is currently busy, it will "
273 				   "be saved when it becomes idle...\n",
274 				   dev_info->segment_name);
275 			dev_info->save_pending = 1;
276 		}
277 	} else if (inbuf[0] == '0') {
278 		if (dev_info->save_pending) {
279 			// device is busy & the user wants to undo his save
280 			// request
281 			dev_info->save_pending = 0;
282 			PRINT_INFO("Pending save for segment %s deactivated\n",
283 					dev_info->segment_name);
284 		}
285 	} else {
286 		up_write(&dcssblk_devices_sem);
287 		return -EINVAL;
288 	}
289 	up_write(&dcssblk_devices_sem);
290 	return count;
291 }
292 
293 /*
294  * device attribute for adding devices
295  */
296 static ssize_t
297 dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
298 {
299 	int rc, i;
300 	struct dcssblk_dev_info *dev_info;
301 	char *local_buf;
302 	unsigned long seg_byte_size;
303 
304 	dev_info = NULL;
305 	if (dev != dcssblk_root_dev) {
306 		rc = -EINVAL;
307 		goto out_nobuf;
308 	}
309 	local_buf = kmalloc(count + 1, GFP_KERNEL);
310 	if (local_buf == NULL) {
311 		rc = -ENOMEM;
312 		goto out_nobuf;
313 	}
314 	/*
315 	 * parse input
316 	 */
317 	for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
318 		local_buf[i] = toupper(buf[i]);
319 	}
320 	local_buf[i] = '\0';
321 	if ((i == 0) || (i > 8)) {
322 		rc = -ENAMETOOLONG;
323 		goto out;
324 	}
325 	/*
326 	 * already loaded?
327 	 */
328 	down_read(&dcssblk_devices_sem);
329 	dev_info = dcssblk_get_device_by_name(local_buf);
330 	up_read(&dcssblk_devices_sem);
331 	if (dev_info != NULL) {
332 		PRINT_WARN("Segment %s already loaded!\n", local_buf);
333 		rc = -EEXIST;
334 		goto out;
335 	}
336 	/*
337 	 * get a struct dcssblk_dev_info
338 	 */
339 	dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL);
340 	if (dev_info == NULL) {
341 		rc = -ENOMEM;
342 		goto out;
343 	}
344 
345 	strcpy(dev_info->segment_name, local_buf);
346 	strlcpy(dev_info->dev.bus_id, local_buf, BUS_ID_SIZE);
347 	dev_info->dev.release = dcssblk_release_segment;
348 	INIT_LIST_HEAD(&dev_info->lh);
349 
350 	dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
351 	if (dev_info->gd == NULL) {
352 		rc = -ENOMEM;
353 		goto free_dev_info;
354 	}
355 	dev_info->gd->major = dcssblk_major;
356 	dev_info->gd->fops = &dcssblk_devops;
357 	dev_info->dcssblk_queue = blk_alloc_queue(GFP_KERNEL);
358 	dev_info->gd->queue = dev_info->dcssblk_queue;
359 	dev_info->gd->private_data = dev_info;
360 	dev_info->gd->driverfs_dev = &dev_info->dev;
361 	blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
362 	blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
363 	/*
364 	 * load the segment
365 	 */
366 	rc = segment_load(local_buf, SEGMENT_SHARED,
367 				&dev_info->start, &dev_info->end);
368 	if (rc < 0) {
369 		segment_warning(rc, dev_info->segment_name);
370 		goto dealloc_gendisk;
371 	}
372 	seg_byte_size = (dev_info->end - dev_info->start + 1);
373 	set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
374 	PRINT_INFO("Loaded segment %s, size = %lu Byte, "
375 		   "capacity = %lu (512 Byte) sectors\n", local_buf,
376 		   seg_byte_size, seg_byte_size >> 9);
377 
378 	dev_info->segment_type = rc;
379 	dev_info->save_pending = 0;
380 	dev_info->is_shared = 1;
381 	dev_info->dev.parent = dcssblk_root_dev;
382 
383 	/*
384 	 * get minor, add to list
385 	 */
386 	down_write(&dcssblk_devices_sem);
387 	rc = dcssblk_assign_free_minor(dev_info);
388 	if (rc) {
389 		up_write(&dcssblk_devices_sem);
390 		PRINT_ERR("No free minor number available! "
391 			  "Unloading segment...\n");
392 		goto unload_seg;
393 	}
394 	sprintf(dev_info->gd->disk_name, "dcssblk%d",
395 		dev_info->gd->first_minor);
396 	list_add_tail(&dev_info->lh, &dcssblk_devices);
397 
398 	if (!try_module_get(THIS_MODULE)) {
399 		rc = -ENODEV;
400 		goto list_del;
401 	}
402 	/*
403 	 * register the device
404 	 */
405 	rc = device_register(&dev_info->dev);
406 	if (rc) {
407 		PRINT_ERR("Segment %s could not be registered RC=%d\n",
408 				local_buf, rc);
409 		module_put(THIS_MODULE);
410 		goto list_del;
411 	}
412 	get_device(&dev_info->dev);
413 	rc = device_create_file(&dev_info->dev, &dev_attr_shared);
414 	if (rc)
415 		goto unregister_dev;
416 	rc = device_create_file(&dev_info->dev, &dev_attr_save);
417 	if (rc)
418 		goto unregister_dev;
419 
420 	add_disk(dev_info->gd);
421 
422 	switch (dev_info->segment_type) {
423 		case SEG_TYPE_SR:
424 		case SEG_TYPE_ER:
425 		case SEG_TYPE_SC:
426 			set_disk_ro(dev_info->gd,1);
427 			break;
428 		default:
429 			set_disk_ro(dev_info->gd,0);
430 			break;
431 	}
432 	PRINT_DEBUG("Segment %s loaded successfully\n", local_buf);
433 	up_write(&dcssblk_devices_sem);
434 	rc = count;
435 	goto out;
436 
437 unregister_dev:
438 	list_del(&dev_info->lh);
439 	blk_cleanup_queue(dev_info->dcssblk_queue);
440 	dev_info->gd->queue = NULL;
441 	put_disk(dev_info->gd);
442 	device_unregister(&dev_info->dev);
443 	segment_unload(dev_info->segment_name);
444 	put_device(&dev_info->dev);
445 	up_write(&dcssblk_devices_sem);
446 	goto out;
447 list_del:
448 	list_del(&dev_info->lh);
449 	up_write(&dcssblk_devices_sem);
450 unload_seg:
451 	segment_unload(local_buf);
452 dealloc_gendisk:
453 	blk_cleanup_queue(dev_info->dcssblk_queue);
454 	dev_info->gd->queue = NULL;
455 	put_disk(dev_info->gd);
456 free_dev_info:
457 	kfree(dev_info);
458 out:
459 	kfree(local_buf);
460 out_nobuf:
461 	return rc;
462 }
463 
464 /*
465  * device attribute for removing devices
466  */
467 static ssize_t
468 dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
469 {
470 	struct dcssblk_dev_info *dev_info;
471 	int rc, i;
472 	char *local_buf;
473 
474 	if (dev != dcssblk_root_dev) {
475 		return -EINVAL;
476 	}
477 	local_buf = kmalloc(count + 1, GFP_KERNEL);
478 	if (local_buf == NULL) {
479 		return -ENOMEM;
480 	}
481 	/*
482 	 * parse input
483 	 */
484 	for (i = 0; ((*(buf+i)!='\0') && (*(buf+i)!='\n') && i < count); i++) {
485 		local_buf[i] = toupper(buf[i]);
486 	}
487 	local_buf[i] = '\0';
488 	if ((i == 0) || (i > 8)) {
489 		rc = -ENAMETOOLONG;
490 		goto out_buf;
491 	}
492 
493 	down_write(&dcssblk_devices_sem);
494 	dev_info = dcssblk_get_device_by_name(local_buf);
495 	if (dev_info == NULL) {
496 		up_write(&dcssblk_devices_sem);
497 		PRINT_WARN("Segment %s is not loaded!\n", local_buf);
498 		rc = -ENODEV;
499 		goto out_buf;
500 	}
501 	if (atomic_read(&dev_info->use_count) != 0) {
502 		up_write(&dcssblk_devices_sem);
503 		PRINT_WARN("Segment %s is in use!\n", local_buf);
504 		rc = -EBUSY;
505 		goto out_buf;
506 	}
507 	list_del(&dev_info->lh);
508 
509 	del_gendisk(dev_info->gd);
510 	blk_cleanup_queue(dev_info->dcssblk_queue);
511 	dev_info->gd->queue = NULL;
512 	put_disk(dev_info->gd);
513 	device_unregister(&dev_info->dev);
514 	segment_unload(dev_info->segment_name);
515 	PRINT_DEBUG("Segment %s unloaded successfully\n",
516 			dev_info->segment_name);
517 	put_device(&dev_info->dev);
518 	up_write(&dcssblk_devices_sem);
519 
520 	rc = count;
521 out_buf:
522 	kfree(local_buf);
523 	return rc;
524 }
525 
526 static int
527 dcssblk_open(struct inode *inode, struct file *filp)
528 {
529 	struct dcssblk_dev_info *dev_info;
530 	int rc;
531 
532 	dev_info = inode->i_bdev->bd_disk->private_data;
533 	if (NULL == dev_info) {
534 		rc = -ENODEV;
535 		goto out;
536 	}
537 	atomic_inc(&dev_info->use_count);
538 	inode->i_bdev->bd_block_size = 4096;
539 	rc = 0;
540 out:
541 	return rc;
542 }
543 
544 static int
545 dcssblk_release(struct inode *inode, struct file *filp)
546 {
547 	struct dcssblk_dev_info *dev_info;
548 	int rc;
549 
550 	dev_info = inode->i_bdev->bd_disk->private_data;
551 	if (NULL == dev_info) {
552 		rc = -ENODEV;
553 		goto out;
554 	}
555 	down_write(&dcssblk_devices_sem);
556 	if (atomic_dec_and_test(&dev_info->use_count)
557 	    && (dev_info->save_pending)) {
558 		PRINT_INFO("Segment %s became idle and is being saved now\n",
559 			    dev_info->segment_name);
560 		segment_save(dev_info->segment_name);
561 		dev_info->save_pending = 0;
562 	}
563 	up_write(&dcssblk_devices_sem);
564 	rc = 0;
565 out:
566 	return rc;
567 }
568 
569 static int
570 dcssblk_make_request(struct request_queue *q, struct bio *bio)
571 {
572 	struct dcssblk_dev_info *dev_info;
573 	struct bio_vec *bvec;
574 	unsigned long index;
575 	unsigned long page_addr;
576 	unsigned long source_addr;
577 	unsigned long bytes_done;
578 	int i;
579 
580 	bytes_done = 0;
581 	dev_info = bio->bi_bdev->bd_disk->private_data;
582 	if (dev_info == NULL)
583 		goto fail;
584 	if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)
585 		/* Request is not page-aligned. */
586 		goto fail;
587 	if (((bio->bi_size >> 9) + bio->bi_sector)
588 			> get_capacity(bio->bi_bdev->bd_disk)) {
589 		/* Request beyond end of DCSS segment. */
590 		goto fail;
591 	}
592 	/* verify data transfer direction */
593 	if (dev_info->is_shared) {
594 		switch (dev_info->segment_type) {
595 		case SEG_TYPE_SR:
596 		case SEG_TYPE_ER:
597 		case SEG_TYPE_SC:
598 			/* cannot write to these segments */
599 			if (bio_data_dir(bio) == WRITE) {
600 				PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
601 				goto fail;
602 			}
603 		}
604 	}
605 
606 	index = (bio->bi_sector >> 3);
607 	bio_for_each_segment(bvec, bio, i) {
608 		page_addr = (unsigned long)
609 			page_address(bvec->bv_page) + bvec->bv_offset;
610 		source_addr = dev_info->start + (index<<12) + bytes_done;
611 		if (unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0)
612 			// More paranoia.
613 			goto fail;
614 		if (bio_data_dir(bio) == READ) {
615 			memcpy((void*)page_addr, (void*)source_addr,
616 				bvec->bv_len);
617 		} else {
618 			memcpy((void*)source_addr, (void*)page_addr,
619 				bvec->bv_len);
620 		}
621 		bytes_done += bvec->bv_len;
622 	}
623 	bio_endio(bio, 0);
624 	return 0;
625 fail:
626 	bio_io_error(bio);
627 	return 0;
628 }
629 
630 static int
631 dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
632 			void **kaddr, unsigned long *pfn)
633 {
634 	struct dcssblk_dev_info *dev_info;
635 	unsigned long pgoff;
636 
637 	dev_info = bdev->bd_disk->private_data;
638 	if (!dev_info)
639 		return -ENODEV;
640 	if (secnum % (PAGE_SIZE/512))
641 		return -EINVAL;
642 	pgoff = secnum / (PAGE_SIZE / 512);
643 	if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
644 		return -ERANGE;
645 	*kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
646 	*pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
647 
648 	return 0;
649 }
650 
651 static void
652 dcssblk_check_params(void)
653 {
654 	int rc, i, j, k;
655 	char buf[9];
656 	struct dcssblk_dev_info *dev_info;
657 
658 	for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
659 	     i++) {
660 		for (j = i; (dcssblk_segments[j] != ',')  &&
661 			    (dcssblk_segments[j] != '\0') &&
662 			    (dcssblk_segments[j] != '(')  &&
663 			    (j - i) < 8; j++)
664 		{
665 			buf[j-i] = dcssblk_segments[j];
666 		}
667 		buf[j-i] = '\0';
668 		rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
669 		if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
670 			for (k = 0; buf[k] != '\0'; k++)
671 				buf[k] = toupper(buf[k]);
672 			if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
673 				down_read(&dcssblk_devices_sem);
674 				dev_info = dcssblk_get_device_by_name(buf);
675 				up_read(&dcssblk_devices_sem);
676 				if (dev_info)
677 					dcssblk_shared_store(&dev_info->dev,
678 							     NULL, "0\n", 2);
679 			}
680 		}
681 		while ((dcssblk_segments[j] != ',') &&
682 		       (dcssblk_segments[j] != '\0'))
683 		{
684 			j++;
685 		}
686 		if (dcssblk_segments[j] == '\0')
687 			break;
688 		i = j;
689 	}
690 }
691 
692 /*
693  * The init/exit functions.
694  */
695 static void __exit
696 dcssblk_exit(void)
697 {
698 	s390_root_dev_unregister(dcssblk_root_dev);
699 	unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
700 }
701 
702 static int __init
703 dcssblk_init(void)
704 {
705 	int rc;
706 
707 	dcssblk_root_dev = s390_root_dev_register("dcssblk");
708 	if (IS_ERR(dcssblk_root_dev))
709 		return PTR_ERR(dcssblk_root_dev);
710 	rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
711 	if (rc) {
712 		s390_root_dev_unregister(dcssblk_root_dev);
713 		return rc;
714 	}
715 	rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
716 	if (rc) {
717 		s390_root_dev_unregister(dcssblk_root_dev);
718 		return rc;
719 	}
720 	rc = register_blkdev(0, DCSSBLK_NAME);
721 	if (rc < 0) {
722 		s390_root_dev_unregister(dcssblk_root_dev);
723 		return rc;
724 	}
725 	dcssblk_major = rc;
726 	init_rwsem(&dcssblk_devices_sem);
727 
728 	dcssblk_check_params();
729 
730 	return 0;
731 }
732 
733 module_init(dcssblk_init);
734 module_exit(dcssblk_exit);
735 
736 module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
737 MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
738 		 "comma-separated list, each name max. 8 chars.\n"
739 		 "Adding \"(local)\" to segment name equals echoing 0 to "
740 		 "/sys/devices/dcssblk/<segment name>/shared after loading "
741 		 "the segment - \n"
742 		 "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\"");
743 
744 MODULE_LICENSE("GPL");
745