7 #define KMSG_COMPONENT "dcssblk"
8 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10 #include <linux/module.h>
12 #include <linux/ctype.h>
13 #include <linux/errno.h>
15 #include <linux/slab.h>
23 #define DCSSBLK_NAME "dcssblk"
24 #define DCSSBLK_MINORS_PER_DISK 1
25 #define DCSSBLK_PARM_LEN 400
26 #define DCSS_BUS_ID_SIZE 20
29 static int dcssblk_release(
struct gendisk *disk,
fmode_t mode);
30 static void dcssblk_make_request(
struct request_queue *
q,
struct bio *bio);
32 void **kaddr,
unsigned long *pfn);
36 static int dcssblk_major;
37 static const struct block_device_operations dcssblk_devops = {
40 .release = dcssblk_release,
41 .direct_access = dcssblk_direct_access,
76 static struct device *dcssblk_root_dev;
85 dcssblk_release_segment(
struct device *
dev)
111 if (dev_info ==
NULL)
113 for (minor = 0; minor < (1<<
MINORBITS); minor++) {
117 if (minor == entry->
gd->first_minor)
123 dev_info->
gd->first_minor = minor;
133 dcssblk_get_device_by_name(
char *
name)
151 dcssblk_get_segment_by_name(
char *name)
171 unsigned long highest_addr;
176 if (highest_addr < entry->
end)
177 highest_addr = entry->
end;
189 unsigned long lowest_addr;
195 if (set_first == 0) {
196 lowest_addr = entry->
start;
199 if (lowest_addr > entry->
start)
200 lowest_addr = entry->
start;
221 if (sort_list ==
NULL)
232 if (sort_list[j].
start > sort_list[i].
start) {
233 memcpy(&temp, &sort_list[i],
235 memcpy(&sort_list[i], &sort_list[j],
237 memcpy(&sort_list[j], &temp,
243 if ((sort_list[i].
end + 1) != sort_list[i+1].start) {
244 pr_err(
"Adjacent DCSSs %s and %s are not "
246 sort_list[i+1].segment_name);
255 SEGMENT_EXCLUSIVE) ||
257 pr_err(
"DCSS %s and DCSS %s have "
258 "incompatible types\n",
260 sort_list[i+1].segment_name);
276 dcssblk_load_segment(
char *name,
struct segment_info **seg_info)
282 *seg_info = dcssblk_get_segment_by_name(name);
284 if (*seg_info !=
NULL)
289 if (*seg_info ==
NULL)
292 strcpy((*seg_info)->segment_name, name);
296 &(*seg_info)->start, &(*seg_info)->end);
301 INIT_LIST_HEAD(&(*seg_info)->lh);
302 (*seg_info)->segment_type =
rc;
307 static void dcssblk_unregister_callback(
struct device *
dev)
333 if ((count > 1) && (inbuf[1] !=
'\n') && (inbuf[1] !=
'\0'))
341 if (inbuf[0] ==
'1') {
359 }
else if (inbuf[0] ==
'0') {
362 pr_err(
"DCSS %s is of type SC and cannot be "
363 "loaded as exclusive-writable\n",
387 pr_err(
"DCSS device %s is removed after a failed access mode "
398 dev_info->
gd->queue =
NULL;
406 dcssblk_shared_store);
430 if ((count > 1) && (inbuf[1] !=
'\n') && (inbuf[1] !=
'\0'))
435 if (inbuf[0] ==
'1') {
438 pr_info(
"All DCSSs that map to device %s are "
446 pr_info(
"Device %s is in use, its DCSSs will be "
447 "saved when it becomes idle\n",
451 }
else if (inbuf[0] ==
'0') {
456 pr_info(
"A pending save request for device %s "
457 "has been canceled\n",
497 static struct attribute *dcssblk_dev_attrs[] = {
498 &dev_attr_shared.attr,
500 &dev_attr_seglist.attr,
504 .attrs = dcssblk_dev_attrs,
507 &dcssblk_dev_attr_group,
517 int rc,
i,
j, num_of_segments;
521 unsigned long seg_byte_size;
525 if (dev != dcssblk_root_dev) {
529 if ((count < 1) || (buf[0] ==
'\0') || (buf[0] ==
'\n')) {
535 if (local_buf ==
NULL) {
544 for (i = 0; ((buf[
i] !=
'\0') && (buf[i] !=
'\n') && i <
count); i++) {
545 for (j = i; (buf[
j] !=
':') &&
551 local_buf[j-
i] =
'\0';
552 if (((j - i) == 0) || ((j - i) > 8)) {
557 rc = dcssblk_load_segment(local_buf, &seg_info);
563 if (num_of_segments == 0) {
566 if (dev_info ==
NULL) {
572 INIT_LIST_HEAD(&dev_info->
seg_list);
578 if ((buf[j] ==
'\0') || (buf[j] ==
'\n'))
583 if ((i > 0) && (buf[i-1] ==
':')) {
587 strlcpy(local_buf, buf, i + 1);
589 rc = dcssblk_is_continuous(dev_info);
593 dev_info->
start = dcssblk_find_lowest_addr(dev_info);
594 dev_info->
end = dcssblk_find_highest_addr(dev_info);
597 dev_info->
dev.release = dcssblk_release_segment;
598 dev_info->
dev.groups = dcssblk_dev_attr_groups;
599 INIT_LIST_HEAD(&dev_info->
lh);
601 if (dev_info->
gd ==
NULL) {
605 dev_info->
gd->major = dcssblk_major;
606 dev_info->
gd->fops = &dcssblk_devops;
610 dev_info->
gd->driverfs_dev = &dev_info->
dev;
614 seg_byte_size = (dev_info->
end - dev_info->
start + 1);
615 set_capacity(dev_info->
gd, seg_byte_size >> 9);
616 pr_info(
"Loaded %s with total size %lu bytes and capacity %lu "
617 "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9);
621 dev_info->
dev.parent = dcssblk_root_dev;
627 if (dcssblk_get_segment_by_name(local_buf)) {
631 rc = dcssblk_assign_free_minor(dev_info);
634 sprintf(dev_info->
gd->disk_name,
"dcssblk%d",
635 dev_info->
gd->first_minor);
669 dev_info->
gd->queue =
NULL;
681 dev_info->
gd->queue =
NULL;
685 if (dev_info ==
NULL)
710 if (dev != dcssblk_root_dev) {
714 if (local_buf ==
NULL) {
720 for (i = 0; ((*(buf+
i)!=
'\0') && (*(buf+
i)!=
'\n') && i <
count); i++) {
724 if ((i == 0) || (i > 8)) {
730 dev_info = dcssblk_get_device_by_name(local_buf);
731 if (dev_info ==
NULL) {
733 pr_warning(
"Device %s cannot be removed because it is not a "
734 "known device\n", local_buf);
740 pr_warning(
"Device %s cannot be removed while it is in "
749 dev_info->
gd->queue =
NULL;
772 dev_info = bdev->bd_disk->private_data;
773 if (
NULL == dev_info) {
778 bdev->bd_block_size = 4096;
785 dcssblk_release(
struct gendisk *disk,
fmode_t mode)
798 pr_info(
"Device %s has become idle and is being saved "
815 struct bio_vec *bvec;
817 unsigned long page_addr;
819 unsigned long bytes_done;
823 dev_info = bio->bi_bdev->bd_disk->private_data;
824 if (dev_info ==
NULL)
826 if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)
829 if (((bio->bi_size >> 9) + bio->bi_sector)
830 > get_capacity(bio->bi_bdev->bd_disk)) {
841 if (bio_data_dir(bio) ==
WRITE) {
843 "is a read-only device\n",
844 dev_name(&dev_info->
dev));
850 index = (bio->bi_sector >> 3);
851 bio_for_each_segment(bvec, bio, i) {
852 page_addr = (
unsigned long)
854 source_addr = dev_info->
start + (index<<12) + bytes_done;
855 if (
unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0)
858 if (bio_data_dir(bio) ==
READ) {
859 memcpy((
void*)page_addr, (
void*)source_addr,
862 memcpy((
void*)source_addr, (
void*)page_addr,
865 bytes_done += bvec->bv_len;
875 void **kaddr,
unsigned long *pfn)
880 dev_info = bdev->
bd_disk->private_data;
895 dcssblk_check_params(
void)
903 for (j = i; (dcssblk_segments[
j] !=
',') &&
904 (dcssblk_segments[j] !=
'\0') &&
905 (dcssblk_segments[
j] !=
'(') &&
908 buf[j-
i] = dcssblk_segments[
j];
911 rc = dcssblk_add_store(dcssblk_root_dev,
NULL, buf, j-i);
912 if ((rc >= 0) && (dcssblk_segments[j] ==
'(')) {
913 for (k = 0; (buf[
k] !=
':') && (buf[k] !=
'\0'); k++)
916 if (!
strncmp(&dcssblk_segments[j],
"(local)", 7)) {
918 dev_info = dcssblk_get_device_by_name(buf);
921 dcssblk_shared_store(&dev_info->
dev,
925 while ((dcssblk_segments[j] !=
',') &&
926 (dcssblk_segments[j] !=
'\0'))
930 if (dcssblk_segments[j] ==
'\0')
939 static int dcssblk_freeze(
struct device *dev)
960 pr_err(
"Suspending the system failed because DCSS device %s "
966 static int dcssblk_restore(
struct device *dev)
983 if (start != entry->
start || end != entry->
end) {
984 pr_err(
"The address range of DCSS %s changed "
985 "while the system was suspended\n",
993 panic(
"fatal dcssblk resume error\n");
996 static int dcssblk_thaw(
struct device *dev)
1001 static const struct dev_pm_ops dcssblk_pm_ops = {
1002 .freeze = dcssblk_freeze,
1003 .thaw = dcssblk_thaw,
1004 .restore = dcssblk_restore,
1011 .pm = &dcssblk_pm_ops,
1039 dcssblk_pdev = platform_device_register_simple(
"dcssblk", -1,
NULL,
1041 if (IS_ERR(dcssblk_pdev)) {
1042 rc = PTR_ERR(dcssblk_pdev);
1047 if (IS_ERR(dcssblk_root_dev)) {
1048 rc = PTR_ERR(dcssblk_root_dev);
1063 dcssblk_check_params();
1080 "comma-separated list, names in each set separated "
1081 "by commas are separated by colons, each set contains "
1082 "names of contiguous segments and each name max. 8 chars.\n"
1083 "Adding \"(local)\" to the end of each set equals echoing 0 "
1084 "to /sys/devices/dcssblk/<device name>/shared after loading "
1085 "the contiguous segments - \n"
1086 "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");