xref: /openbmc/linux/drivers/s390/block/dcssblk.c (revision 8569c914)
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 static int dcssblk_open(struct inode *inode, struct file *filp);
35 static int dcssblk_release(struct inode *inode, struct file *filp);
36 static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
37 static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
38 				 void **kaddr, unsigned long *pfn);
39 
40 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
41 
42 static int dcssblk_major;
43 static struct block_device_operations dcssblk_devops = {
44 	.owner   	= THIS_MODULE,
45 	.open    	= dcssblk_open,
46 	.release 	= dcssblk_release,
47 	.direct_access 	= dcssblk_direct_access,
48 };
49 
50 struct dcssblk_dev_info {
51 	struct list_head lh;
52 	struct device dev;
53 	char segment_name[BUS_ID_SIZE];
54 	atomic_t use_count;
55 	struct gendisk *gd;
56 	unsigned long start;
57 	unsigned long end;
58 	int segment_type;
59 	unsigned char save_pending;
60 	unsigned char is_shared;
61 	struct request_queue *dcssblk_queue;
62 	int num_of_segments;
63 	struct list_head seg_list;
64 };
65 
66 struct segment_info {
67 	struct list_head lh;
68 	char segment_name[BUS_ID_SIZE];
69 	unsigned long start;
70 	unsigned long end;
71 	int segment_type;
72 };
73 
74 static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
75 				  size_t count);
76 static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
77 				  size_t count);
78 static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
79 				  size_t count);
80 static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
81 static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
82 				  size_t count);
83 static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
84 static ssize_t dcssblk_seglist_show(struct device *dev,
85 				struct device_attribute *attr,
86 				char *buf);
87 
88 static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
89 static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
90 static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
91 		   dcssblk_save_store);
92 static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
93 		   dcssblk_shared_store);
94 static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
95 
96 static struct device *dcssblk_root_dev;
97 
98 static LIST_HEAD(dcssblk_devices);
99 static struct rw_semaphore dcssblk_devices_sem;
100 
101 /*
102  * release function for segment device.
103  */
104 static void
105 dcssblk_release_segment(struct device *dev)
106 {
107 	struct dcssblk_dev_info *dev_info;
108 	struct segment_info *entry, *temp;
109 
110 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
111 	list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) {
112 		list_del(&entry->lh);
113 		kfree(entry);
114 	}
115 	kfree(dev_info);
116 	module_put(THIS_MODULE);
117 }
118 
119 /*
120  * get a minor number. needs to be called with
121  * down_write(&dcssblk_devices_sem) and the
122  * device needs to be enqueued before the semaphore is
123  * freed.
124  */
125 static int
126 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
127 {
128 	int minor, found;
129 	struct dcssblk_dev_info *entry;
130 
131 	if (dev_info == NULL)
132 		return -EINVAL;
133 	for (minor = 0; minor < (1<<MINORBITS); minor++) {
134 		found = 0;
135 		// test if minor available
136 		list_for_each_entry(entry, &dcssblk_devices, lh)
137 			if (minor == MINOR(disk_devt(entry->gd)))
138 				found++;
139 		if (!found) break; // got unused minor
140 	}
141 	if (found)
142 		return -EBUSY;
143 	dev_info->gd->first_minor = minor;
144 	return 0;
145 }
146 
147 /*
148  * get the struct dcssblk_dev_info from dcssblk_devices
149  * for the given name.
150  * down_read(&dcssblk_devices_sem) must be held.
151  */
152 static struct dcssblk_dev_info *
153 dcssblk_get_device_by_name(char *name)
154 {
155 	struct dcssblk_dev_info *entry;
156 
157 	list_for_each_entry(entry, &dcssblk_devices, lh) {
158 		if (!strcmp(name, entry->segment_name)) {
159 			return entry;
160 		}
161 	}
162 	return NULL;
163 }
164 
165 /*
166  * get the struct segment_info from seg_list
167  * for the given name.
168  * down_read(&dcssblk_devices_sem) must be held.
169  */
170 static struct segment_info *
171 dcssblk_get_segment_by_name(char *name)
172 {
173 	struct dcssblk_dev_info *dev_info;
174 	struct segment_info *entry;
175 
176 	list_for_each_entry(dev_info, &dcssblk_devices, lh) {
177 		list_for_each_entry(entry, &dev_info->seg_list, lh) {
178 			if (!strcmp(name, entry->segment_name))
179 				return entry;
180 		}
181 	}
182 	return NULL;
183 }
184 
185 /*
186  * get the highest address of the multi-segment block.
187  */
188 static unsigned long
189 dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info)
190 {
191 	unsigned long highest_addr;
192 	struct segment_info *entry;
193 
194 	highest_addr = 0;
195 	list_for_each_entry(entry, &dev_info->seg_list, lh) {
196 		if (highest_addr < entry->end)
197 			highest_addr = entry->end;
198 	}
199 	return highest_addr;
200 }
201 
202 /*
203  * get the lowest address of the multi-segment block.
204  */
205 static unsigned long
206 dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info)
207 {
208 	int set_first;
209 	unsigned long lowest_addr;
210 	struct segment_info *entry;
211 
212 	set_first = 0;
213 	lowest_addr = 0;
214 	list_for_each_entry(entry, &dev_info->seg_list, lh) {
215 		if (set_first == 0) {
216 			lowest_addr = entry->start;
217 			set_first = 1;
218 		} else {
219 			if (lowest_addr > entry->start)
220 				lowest_addr = entry->start;
221 		}
222 	}
223 	return lowest_addr;
224 }
225 
226 /*
227  * Check continuity of segments.
228  */
229 static int
230 dcssblk_is_continuous(struct dcssblk_dev_info *dev_info)
231 {
232 	int i, j, rc;
233 	struct segment_info *sort_list, *entry, temp;
234 
235 	if (dev_info->num_of_segments <= 1)
236 		return 0;
237 
238 	sort_list = kzalloc(
239 			sizeof(struct segment_info) * dev_info->num_of_segments,
240 			GFP_KERNEL);
241 	if (sort_list == NULL)
242 		return -ENOMEM;
243 	i = 0;
244 	list_for_each_entry(entry, &dev_info->seg_list, lh) {
245 		memcpy(&sort_list[i], entry, sizeof(struct segment_info));
246 		i++;
247 	}
248 
249 	/* sort segments */
250 	for (i = 0; i < dev_info->num_of_segments; i++)
251 		for (j = 0; j < dev_info->num_of_segments; j++)
252 			if (sort_list[j].start > sort_list[i].start) {
253 				memcpy(&temp, &sort_list[i],
254 					sizeof(struct segment_info));
255 				memcpy(&sort_list[i], &sort_list[j],
256 					sizeof(struct segment_info));
257 				memcpy(&sort_list[j], &temp,
258 					sizeof(struct segment_info));
259 			}
260 
261 	/* check continuity */
262 	for (i = 0; i < dev_info->num_of_segments - 1; i++) {
263 		if ((sort_list[i].end + 1) != sort_list[i+1].start) {
264 			PRINT_ERR("Segment %s is not contiguous with "
265 				"segment %s\n",
266 				sort_list[i].segment_name,
267 				sort_list[i+1].segment_name);
268 			rc = -EINVAL;
269 			goto out;
270 		}
271 		/* EN and EW are allowed in a block device */
272 		if (sort_list[i].segment_type != sort_list[i+1].segment_type) {
273 			if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) ||
274 				(sort_list[i].segment_type == SEG_TYPE_ER) ||
275 				!(sort_list[i+1].segment_type &
276 				SEGMENT_EXCLUSIVE) ||
277 				(sort_list[i+1].segment_type == SEG_TYPE_ER)) {
278 				PRINT_ERR("Segment %s has different type from "
279 					"segment %s\n",
280 					sort_list[i].segment_name,
281 					sort_list[i+1].segment_name);
282 				rc = -EINVAL;
283 				goto out;
284 			}
285 		}
286 	}
287 	rc = 0;
288 out:
289 	kfree(sort_list);
290 	return rc;
291 }
292 
293 /*
294  * Load a segment
295  */
296 static int
297 dcssblk_load_segment(char *name, struct segment_info **seg_info)
298 {
299 	int rc;
300 
301 	/* already loaded? */
302 	down_read(&dcssblk_devices_sem);
303 	*seg_info = dcssblk_get_segment_by_name(name);
304 	up_read(&dcssblk_devices_sem);
305 	if (*seg_info != NULL)
306 		return -EEXIST;
307 
308 	/* get a struct segment_info */
309 	*seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL);
310 	if (*seg_info == NULL)
311 		return -ENOMEM;
312 
313 	strcpy((*seg_info)->segment_name, name);
314 
315 	/* load the segment */
316 	rc = segment_load(name, SEGMENT_SHARED,
317 			&(*seg_info)->start, &(*seg_info)->end);
318 	if (rc < 0) {
319 		segment_warning(rc, (*seg_info)->segment_name);
320 		kfree(*seg_info);
321 	} else {
322 		INIT_LIST_HEAD(&(*seg_info)->lh);
323 		(*seg_info)->segment_type = rc;
324 	}
325 	return rc;
326 }
327 
328 static void dcssblk_unregister_callback(struct device *dev)
329 {
330 	device_unregister(dev);
331 	put_device(dev);
332 }
333 
334 /*
335  * device attribute for switching shared/nonshared (exclusive)
336  * operation (show + store)
337  */
338 static ssize_t
339 dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf)
340 {
341 	struct dcssblk_dev_info *dev_info;
342 
343 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
344 	return sprintf(buf, dev_info->is_shared ? "1\n" : "0\n");
345 }
346 
347 static ssize_t
348 dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
349 {
350 	struct dcssblk_dev_info *dev_info;
351 	struct segment_info *entry, *temp;
352 	int rc;
353 
354 	if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
355 		return -EINVAL;
356 	down_write(&dcssblk_devices_sem);
357 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
358 	if (atomic_read(&dev_info->use_count)) {
359 		rc = -EBUSY;
360 		goto out;
361 	}
362 	if (inbuf[0] == '1') {
363 		/* reload segments in shared mode */
364 		list_for_each_entry(entry, &dev_info->seg_list, lh) {
365 			rc = segment_modify_shared(entry->segment_name,
366 						SEGMENT_SHARED);
367 			if (rc < 0) {
368 				BUG_ON(rc == -EINVAL);
369 				if (rc != -EAGAIN)
370 					goto removeseg;
371 			}
372 		}
373 		dev_info->is_shared = 1;
374 		switch (dev_info->segment_type) {
375 		case SEG_TYPE_SR:
376 		case SEG_TYPE_ER:
377 		case SEG_TYPE_SC:
378 			set_disk_ro(dev_info->gd, 1);
379 		}
380 	} else if (inbuf[0] == '0') {
381 		/* reload segments in exclusive mode */
382 		if (dev_info->segment_type == SEG_TYPE_SC) {
383 			PRINT_ERR("Segment type SC (%s) cannot be loaded in "
384 				"non-shared mode\n", dev_info->segment_name);
385 			rc = -EINVAL;
386 			goto out;
387 		}
388 		list_for_each_entry(entry, &dev_info->seg_list, lh) {
389 			rc = segment_modify_shared(entry->segment_name,
390 						   SEGMENT_EXCLUSIVE);
391 			if (rc < 0) {
392 				BUG_ON(rc == -EINVAL);
393 				if (rc != -EAGAIN)
394 					goto removeseg;
395 			}
396 		}
397 		dev_info->is_shared = 0;
398 		set_disk_ro(dev_info->gd, 0);
399 	} else {
400 		rc = -EINVAL;
401 		goto out;
402 	}
403 	rc = count;
404 	goto out;
405 
406 removeseg:
407 	PRINT_ERR("Could not reload segment(s) of the device %s, removing "
408 		"segment(s) now!\n",
409 		dev_info->segment_name);
410 	temp = entry;
411 	list_for_each_entry(entry, &dev_info->seg_list, lh) {
412 		if (entry != temp)
413 			segment_unload(entry->segment_name);
414 	}
415 	list_del(&dev_info->lh);
416 
417 	del_gendisk(dev_info->gd);
418 	blk_cleanup_queue(dev_info->dcssblk_queue);
419 	dev_info->gd->queue = NULL;
420 	put_disk(dev_info->gd);
421 	rc = device_schedule_callback(dev, dcssblk_unregister_callback);
422 out:
423 	up_write(&dcssblk_devices_sem);
424 	return rc;
425 }
426 
427 /*
428  * device attribute for save operation on current copy
429  * of the segment. If the segment is busy, saving will
430  * become pending until it gets released, which can be
431  * undone by storing a non-true value to this entry.
432  * (show + store)
433  */
434 static ssize_t
435 dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf)
436 {
437 	struct dcssblk_dev_info *dev_info;
438 
439 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
440 	return sprintf(buf, dev_info->save_pending ? "1\n" : "0\n");
441 }
442 
443 static ssize_t
444 dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
445 {
446 	struct dcssblk_dev_info *dev_info;
447 	struct segment_info *entry;
448 
449 	if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
450 		return -EINVAL;
451 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
452 
453 	down_write(&dcssblk_devices_sem);
454 	if (inbuf[0] == '1') {
455 		if (atomic_read(&dev_info->use_count) == 0) {
456 			// device is idle => we save immediately
457 			PRINT_INFO("Saving segment(s) of the device %s\n",
458 				   dev_info->segment_name);
459 			list_for_each_entry(entry, &dev_info->seg_list, lh) {
460 				segment_save(entry->segment_name);
461 			}
462 		}  else {
463 			// device is busy => we save it when it becomes
464 			// idle in dcssblk_release
465 			PRINT_INFO("Device %s is currently busy, segment(s) "
466 				   "will be saved when it becomes idle...\n",
467 				   dev_info->segment_name);
468 			dev_info->save_pending = 1;
469 		}
470 	} else if (inbuf[0] == '0') {
471 		if (dev_info->save_pending) {
472 			// device is busy & the user wants to undo his save
473 			// request
474 			dev_info->save_pending = 0;
475 			PRINT_INFO("Pending save for segment(s) of the device "
476 					"%s deactivated\n",
477 					dev_info->segment_name);
478 		}
479 	} else {
480 		up_write(&dcssblk_devices_sem);
481 		return -EINVAL;
482 	}
483 	up_write(&dcssblk_devices_sem);
484 	return count;
485 }
486 
487 /*
488  * device attribute for showing all segments in a device
489  */
490 static ssize_t
491 dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
492 		char *buf)
493 {
494 	int i;
495 
496 	struct dcssblk_dev_info *dev_info;
497 	struct segment_info *entry;
498 
499 	down_read(&dcssblk_devices_sem);
500 	dev_info = container_of(dev, struct dcssblk_dev_info, dev);
501 	i = 0;
502 	buf[0] = '\0';
503 	list_for_each_entry(entry, &dev_info->seg_list, lh) {
504 		strcpy(&buf[i], entry->segment_name);
505 		i += strlen(entry->segment_name);
506 		buf[i] = '\n';
507 		i++;
508 	}
509 	up_read(&dcssblk_devices_sem);
510 	return i;
511 }
512 
513 /*
514  * device attribute for adding devices
515  */
516 static ssize_t
517 dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
518 {
519 	int rc, i, j, num_of_segments;
520 	struct dcssblk_dev_info *dev_info;
521 	struct segment_info *seg_info, *temp;
522 	char *local_buf;
523 	unsigned long seg_byte_size;
524 
525 	dev_info = NULL;
526 	seg_info = NULL;
527 	if (dev != dcssblk_root_dev) {
528 		rc = -EINVAL;
529 		goto out_nobuf;
530 	}
531 	if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) {
532 		rc = -ENAMETOOLONG;
533 		goto out_nobuf;
534 	}
535 
536 	local_buf = kmalloc(count + 1, GFP_KERNEL);
537 	if (local_buf == NULL) {
538 		rc = -ENOMEM;
539 		goto out_nobuf;
540 	}
541 
542 	/*
543 	 * parse input
544 	 */
545 	num_of_segments = 0;
546 	for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
547 		for (j = i; (buf[j] != ':') &&
548 			(buf[j] != '\0') &&
549 			(buf[j] != '\n') &&
550 			j < count; j++) {
551 			local_buf[j-i] = toupper(buf[j]);
552 		}
553 		local_buf[j-i] = '\0';
554 		if (((j - i) == 0) || ((j - i) > 8)) {
555 			rc = -ENAMETOOLONG;
556 			goto seg_list_del;
557 		}
558 
559 		rc = dcssblk_load_segment(local_buf, &seg_info);
560 		if (rc < 0)
561 			goto seg_list_del;
562 		/*
563 		 * get a struct dcssblk_dev_info
564 		 */
565 		if (num_of_segments == 0) {
566 			dev_info = kzalloc(sizeof(struct dcssblk_dev_info),
567 					GFP_KERNEL);
568 			if (dev_info == NULL) {
569 				rc = -ENOMEM;
570 				goto out;
571 			}
572 			strcpy(dev_info->segment_name, local_buf);
573 			dev_info->segment_type = seg_info->segment_type;
574 			INIT_LIST_HEAD(&dev_info->seg_list);
575 		}
576 		list_add_tail(&seg_info->lh, &dev_info->seg_list);
577 		num_of_segments++;
578 		i = j;
579 
580 		if ((buf[j] == '\0') || (buf[j] == '\n'))
581 			break;
582 	}
583 
584 	/* no trailing colon at the end of the input */
585 	if ((i > 0) && (buf[i-1] == ':')) {
586 		rc = -ENAMETOOLONG;
587 		goto seg_list_del;
588 	}
589 	strlcpy(local_buf, buf, i + 1);
590 	dev_info->num_of_segments = num_of_segments;
591 	rc = dcssblk_is_continuous(dev_info);
592 	if (rc < 0)
593 		goto seg_list_del;
594 
595 	dev_info->start = dcssblk_find_lowest_addr(dev_info);
596 	dev_info->end = dcssblk_find_highest_addr(dev_info);
597 
598 	dev_set_name(&dev_info->dev, dev_info->segment_name);
599 	dev_info->dev.release = dcssblk_release_segment;
600 	INIT_LIST_HEAD(&dev_info->lh);
601 	dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
602 	if (dev_info->gd == NULL) {
603 		rc = -ENOMEM;
604 		goto seg_list_del;
605 	}
606 	dev_info->gd->major = dcssblk_major;
607 	dev_info->gd->fops = &dcssblk_devops;
608 	dev_info->dcssblk_queue = blk_alloc_queue(GFP_KERNEL);
609 	dev_info->gd->queue = dev_info->dcssblk_queue;
610 	dev_info->gd->private_data = dev_info;
611 	dev_info->gd->driverfs_dev = &dev_info->dev;
612 	blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
613 	blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
614 
615 	seg_byte_size = (dev_info->end - dev_info->start + 1);
616 	set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
617 	PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, "
618 		   "capacity = %lu (512 Byte) sectors\n", local_buf,
619 		   seg_byte_size, seg_byte_size >> 9);
620 
621 	dev_info->save_pending = 0;
622 	dev_info->is_shared = 1;
623 	dev_info->dev.parent = dcssblk_root_dev;
624 
625 	/*
626 	 *get minor, add to list
627 	 */
628 	down_write(&dcssblk_devices_sem);
629 	if (dcssblk_get_segment_by_name(local_buf)) {
630 		rc = -EEXIST;
631 		goto release_gd;
632 	}
633 	rc = dcssblk_assign_free_minor(dev_info);
634 	if (rc)
635 		goto release_gd;
636 	sprintf(dev_info->gd->disk_name, "dcssblk%d",
637 		MINOR(disk_devt(dev_info->gd)));
638 	list_add_tail(&dev_info->lh, &dcssblk_devices);
639 
640 	if (!try_module_get(THIS_MODULE)) {
641 		rc = -ENODEV;
642 		goto dev_list_del;
643 	}
644 	/*
645 	 * register the device
646 	 */
647 	rc = device_register(&dev_info->dev);
648 	if (rc) {
649 		module_put(THIS_MODULE);
650 		goto dev_list_del;
651 	}
652 	get_device(&dev_info->dev);
653 	rc = device_create_file(&dev_info->dev, &dev_attr_shared);
654 	if (rc)
655 		goto unregister_dev;
656 	rc = device_create_file(&dev_info->dev, &dev_attr_save);
657 	if (rc)
658 		goto unregister_dev;
659 	rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
660 	if (rc)
661 		goto unregister_dev;
662 
663 	add_disk(dev_info->gd);
664 
665 	switch (dev_info->segment_type) {
666 		case SEG_TYPE_SR:
667 		case SEG_TYPE_ER:
668 		case SEG_TYPE_SC:
669 			set_disk_ro(dev_info->gd,1);
670 			break;
671 		default:
672 			set_disk_ro(dev_info->gd,0);
673 			break;
674 	}
675 	up_write(&dcssblk_devices_sem);
676 	rc = count;
677 	goto out;
678 
679 unregister_dev:
680 	list_del(&dev_info->lh);
681 	blk_cleanup_queue(dev_info->dcssblk_queue);
682 	dev_info->gd->queue = NULL;
683 	put_disk(dev_info->gd);
684 	device_unregister(&dev_info->dev);
685 	list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
686 		segment_unload(seg_info->segment_name);
687 	}
688 	put_device(&dev_info->dev);
689 	up_write(&dcssblk_devices_sem);
690 	goto out;
691 dev_list_del:
692 	list_del(&dev_info->lh);
693 release_gd:
694 	blk_cleanup_queue(dev_info->dcssblk_queue);
695 	dev_info->gd->queue = NULL;
696 	put_disk(dev_info->gd);
697 	up_write(&dcssblk_devices_sem);
698 seg_list_del:
699 	if (dev_info == NULL)
700 		goto out;
701 	list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) {
702 		list_del(&seg_info->lh);
703 		segment_unload(seg_info->segment_name);
704 		kfree(seg_info);
705 	}
706 	kfree(dev_info);
707 out:
708 	kfree(local_buf);
709 out_nobuf:
710 	return rc;
711 }
712 
713 /*
714  * device attribute for removing devices
715  */
716 static ssize_t
717 dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
718 {
719 	struct dcssblk_dev_info *dev_info;
720 	struct segment_info *entry;
721 	int rc, i;
722 	char *local_buf;
723 
724 	if (dev != dcssblk_root_dev) {
725 		return -EINVAL;
726 	}
727 	local_buf = kmalloc(count + 1, GFP_KERNEL);
728 	if (local_buf == NULL) {
729 		return -ENOMEM;
730 	}
731 	/*
732 	 * parse input
733 	 */
734 	for (i = 0; ((*(buf+i)!='\0') && (*(buf+i)!='\n') && i < count); i++) {
735 		local_buf[i] = toupper(buf[i]);
736 	}
737 	local_buf[i] = '\0';
738 	if ((i == 0) || (i > 8)) {
739 		rc = -ENAMETOOLONG;
740 		goto out_buf;
741 	}
742 
743 	down_write(&dcssblk_devices_sem);
744 	dev_info = dcssblk_get_device_by_name(local_buf);
745 	if (dev_info == NULL) {
746 		up_write(&dcssblk_devices_sem);
747 		PRINT_WARN("Device %s is not loaded!\n", local_buf);
748 		rc = -ENODEV;
749 		goto out_buf;
750 	}
751 	if (atomic_read(&dev_info->use_count) != 0) {
752 		up_write(&dcssblk_devices_sem);
753 		PRINT_WARN("Device %s is in use!\n", local_buf);
754 		rc = -EBUSY;
755 		goto out_buf;
756 	}
757 
758 	list_del(&dev_info->lh);
759 	del_gendisk(dev_info->gd);
760 	blk_cleanup_queue(dev_info->dcssblk_queue);
761 	dev_info->gd->queue = NULL;
762 	put_disk(dev_info->gd);
763 	device_unregister(&dev_info->dev);
764 
765 	/* unload all related segments */
766 	list_for_each_entry(entry, &dev_info->seg_list, lh)
767 		segment_unload(entry->segment_name);
768 
769 	put_device(&dev_info->dev);
770 	up_write(&dcssblk_devices_sem);
771 
772 	rc = count;
773 out_buf:
774 	kfree(local_buf);
775 	return rc;
776 }
777 
778 static int
779 dcssblk_open(struct inode *inode, struct file *filp)
780 {
781 	struct dcssblk_dev_info *dev_info;
782 	int rc;
783 
784 	dev_info = inode->i_bdev->bd_disk->private_data;
785 	if (NULL == dev_info) {
786 		rc = -ENODEV;
787 		goto out;
788 	}
789 	atomic_inc(&dev_info->use_count);
790 	inode->i_bdev->bd_block_size = 4096;
791 	rc = 0;
792 out:
793 	return rc;
794 }
795 
796 static int
797 dcssblk_release(struct inode *inode, struct file *filp)
798 {
799 	struct dcssblk_dev_info *dev_info;
800 	struct segment_info *entry;
801 	int rc;
802 
803 	dev_info = inode->i_bdev->bd_disk->private_data;
804 	if (NULL == dev_info) {
805 		rc = -ENODEV;
806 		goto out;
807 	}
808 	down_write(&dcssblk_devices_sem);
809 	if (atomic_dec_and_test(&dev_info->use_count)
810 	    && (dev_info->save_pending)) {
811 		PRINT_INFO("Device %s became idle and is being saved now\n",
812 			    dev_info->segment_name);
813 		list_for_each_entry(entry, &dev_info->seg_list, lh) {
814 			segment_save(entry->segment_name);
815 		}
816 		dev_info->save_pending = 0;
817 	}
818 	up_write(&dcssblk_devices_sem);
819 	rc = 0;
820 out:
821 	return rc;
822 }
823 
824 static int
825 dcssblk_make_request(struct request_queue *q, struct bio *bio)
826 {
827 	struct dcssblk_dev_info *dev_info;
828 	struct bio_vec *bvec;
829 	unsigned long index;
830 	unsigned long page_addr;
831 	unsigned long source_addr;
832 	unsigned long bytes_done;
833 	int i;
834 
835 	bytes_done = 0;
836 	dev_info = bio->bi_bdev->bd_disk->private_data;
837 	if (dev_info == NULL)
838 		goto fail;
839 	if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)
840 		/* Request is not page-aligned. */
841 		goto fail;
842 	if (((bio->bi_size >> 9) + bio->bi_sector)
843 			> get_capacity(bio->bi_bdev->bd_disk)) {
844 		/* Request beyond end of DCSS segment. */
845 		goto fail;
846 	}
847 	/* verify data transfer direction */
848 	if (dev_info->is_shared) {
849 		switch (dev_info->segment_type) {
850 		case SEG_TYPE_SR:
851 		case SEG_TYPE_ER:
852 		case SEG_TYPE_SC:
853 			/* cannot write to these segments */
854 			if (bio_data_dir(bio) == WRITE) {
855 				PRINT_WARN("rejecting write to ro device %s\n",
856 					   dev_name(&dev_info->dev));
857 				goto fail;
858 			}
859 		}
860 	}
861 
862 	index = (bio->bi_sector >> 3);
863 	bio_for_each_segment(bvec, bio, i) {
864 		page_addr = (unsigned long)
865 			page_address(bvec->bv_page) + bvec->bv_offset;
866 		source_addr = dev_info->start + (index<<12) + bytes_done;
867 		if (unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0)
868 			// More paranoia.
869 			goto fail;
870 		if (bio_data_dir(bio) == READ) {
871 			memcpy((void*)page_addr, (void*)source_addr,
872 				bvec->bv_len);
873 		} else {
874 			memcpy((void*)source_addr, (void*)page_addr,
875 				bvec->bv_len);
876 		}
877 		bytes_done += bvec->bv_len;
878 	}
879 	bio_endio(bio, 0);
880 	return 0;
881 fail:
882 	bio_io_error(bio);
883 	return 0;
884 }
885 
886 static int
887 dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
888 			void **kaddr, unsigned long *pfn)
889 {
890 	struct dcssblk_dev_info *dev_info;
891 	unsigned long pgoff;
892 
893 	dev_info = bdev->bd_disk->private_data;
894 	if (!dev_info)
895 		return -ENODEV;
896 	if (secnum % (PAGE_SIZE/512))
897 		return -EINVAL;
898 	pgoff = secnum / (PAGE_SIZE / 512);
899 	if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
900 		return -ERANGE;
901 	*kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
902 	*pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
903 
904 	return 0;
905 }
906 
907 static void
908 dcssblk_check_params(void)
909 {
910 	int rc, i, j, k;
911 	char buf[DCSSBLK_PARM_LEN + 1];
912 	struct dcssblk_dev_info *dev_info;
913 
914 	for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
915 	     i++) {
916 		for (j = i; (dcssblk_segments[j] != ',')  &&
917 			    (dcssblk_segments[j] != '\0') &&
918 			    (dcssblk_segments[j] != '(')  &&
919 			    (j < DCSSBLK_PARM_LEN); j++)
920 		{
921 			buf[j-i] = dcssblk_segments[j];
922 		}
923 		buf[j-i] = '\0';
924 		rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
925 		if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
926 			for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++)
927 				buf[k] = toupper(buf[k]);
928 			buf[k] = '\0';
929 			if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
930 				down_read(&dcssblk_devices_sem);
931 				dev_info = dcssblk_get_device_by_name(buf);
932 				up_read(&dcssblk_devices_sem);
933 				if (dev_info)
934 					dcssblk_shared_store(&dev_info->dev,
935 							     NULL, "0\n", 2);
936 			}
937 		}
938 		while ((dcssblk_segments[j] != ',') &&
939 		       (dcssblk_segments[j] != '\0'))
940 		{
941 			j++;
942 		}
943 		if (dcssblk_segments[j] == '\0')
944 			break;
945 		i = j;
946 	}
947 }
948 
949 /*
950  * The init/exit functions.
951  */
952 static void __exit
953 dcssblk_exit(void)
954 {
955 	s390_root_dev_unregister(dcssblk_root_dev);
956 	unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
957 }
958 
959 static int __init
960 dcssblk_init(void)
961 {
962 	int rc;
963 
964 	dcssblk_root_dev = s390_root_dev_register("dcssblk");
965 	if (IS_ERR(dcssblk_root_dev))
966 		return PTR_ERR(dcssblk_root_dev);
967 	rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
968 	if (rc) {
969 		s390_root_dev_unregister(dcssblk_root_dev);
970 		return rc;
971 	}
972 	rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
973 	if (rc) {
974 		s390_root_dev_unregister(dcssblk_root_dev);
975 		return rc;
976 	}
977 	rc = register_blkdev(0, DCSSBLK_NAME);
978 	if (rc < 0) {
979 		s390_root_dev_unregister(dcssblk_root_dev);
980 		return rc;
981 	}
982 	dcssblk_major = rc;
983 	init_rwsem(&dcssblk_devices_sem);
984 
985 	dcssblk_check_params();
986 
987 	return 0;
988 }
989 
990 module_init(dcssblk_init);
991 module_exit(dcssblk_exit);
992 
993 module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
994 MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
995 		 "comma-separated list, names in each set separated "
996 		 "by commas are separated by colons, each set contains "
997 		 "names of contiguous segments and each name max. 8 chars.\n"
998 		 "Adding \"(local)\" to the end of each set equals echoing 0 "
999 		 "to /sys/devices/dcssblk/<device name>/shared after loading "
1000 		 "the contiguous segments - \n"
1001 		 "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");
1002 
1003 MODULE_LICENSE("GPL");
1004