1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * dcssblk.c -- the S/390 block driver for dcss memory 4 * 5 * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer 6 */ 7 8 #define KMSG_COMPONENT "dcssblk" 9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 10 11 #include <linux/module.h> 12 #include <linux/moduleparam.h> 13 #include <linux/ctype.h> 14 #include <linux/errno.h> 15 #include <linux/init.h> 16 #include <linux/slab.h> 17 #include <linux/blkdev.h> 18 #include <linux/completion.h> 19 #include <linux/interrupt.h> 20 #include <linux/platform_device.h> 21 #include <linux/pfn_t.h> 22 #include <linux/uio.h> 23 #include <linux/dax.h> 24 #include <asm/extmem.h> 25 #include <asm/io.h> 26 27 #define DCSSBLK_NAME "dcssblk" 28 #define DCSSBLK_MINORS_PER_DISK 1 29 #define DCSSBLK_PARM_LEN 400 30 #define DCSS_BUS_ID_SIZE 20 31 32 static int dcssblk_open(struct block_device *bdev, fmode_t mode); 33 static void dcssblk_release(struct gendisk *disk, fmode_t mode); 34 static blk_qc_t dcssblk_make_request(struct request_queue *q, 35 struct bio *bio); 36 static long dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, 37 long nr_pages, void **kaddr, pfn_t *pfn); 38 39 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; 40 41 static int dcssblk_major; 42 static const struct block_device_operations dcssblk_devops = { 43 .owner = THIS_MODULE, 44 .open = dcssblk_open, 45 .release = dcssblk_release, 46 }; 47 48 static size_t dcssblk_dax_copy_from_iter(struct dax_device *dax_dev, 49 pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i) 50 { 51 return copy_from_iter(addr, bytes, i); 52 } 53 54 static size_t dcssblk_dax_copy_to_iter(struct dax_device *dax_dev, 55 pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i) 56 { 57 return copy_to_iter(addr, bytes, i); 58 } 59 60 static const struct dax_operations dcssblk_dax_ops = { 61 .direct_access = dcssblk_dax_direct_access, 62 .copy_from_iter = dcssblk_dax_copy_from_iter, 63 .copy_to_iter = dcssblk_dax_copy_to_iter, 64 }; 65 66 struct dcssblk_dev_info { 67 struct list_head lh; 68 struct device dev; 69 char segment_name[DCSS_BUS_ID_SIZE]; 70 atomic_t use_count; 71 struct gendisk *gd; 72 unsigned long start; 73 unsigned long end; 74 int segment_type; 75 unsigned char save_pending; 76 unsigned char is_shared; 77 struct request_queue *dcssblk_queue; 78 int num_of_segments; 79 struct list_head seg_list; 80 struct dax_device *dax_dev; 81 }; 82 83 struct segment_info { 84 struct list_head lh; 85 char segment_name[DCSS_BUS_ID_SIZE]; 86 unsigned long start; 87 unsigned long end; 88 int segment_type; 89 }; 90 91 static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, 92 size_t count); 93 static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, 94 size_t count); 95 96 static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); 97 static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); 98 99 static struct device *dcssblk_root_dev; 100 101 static LIST_HEAD(dcssblk_devices); 102 static struct rw_semaphore dcssblk_devices_sem; 103 104 /* 105 * release function for segment device. 106 */ 107 static void 108 dcssblk_release_segment(struct device *dev) 109 { 110 struct dcssblk_dev_info *dev_info; 111 struct segment_info *entry, *temp; 112 113 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 114 list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) { 115 list_del(&entry->lh); 116 kfree(entry); 117 } 118 kfree(dev_info); 119 module_put(THIS_MODULE); 120 } 121 122 /* 123 * get a minor number. needs to be called with 124 * down_write(&dcssblk_devices_sem) and the 125 * device needs to be enqueued before the semaphore is 126 * freed. 127 */ 128 static int 129 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) 130 { 131 int minor, found; 132 struct dcssblk_dev_info *entry; 133 134 if (dev_info == NULL) 135 return -EINVAL; 136 for (minor = 0; minor < (1<<MINORBITS); minor++) { 137 found = 0; 138 // test if minor available 139 list_for_each_entry(entry, &dcssblk_devices, lh) 140 if (minor == entry->gd->first_minor) 141 found++; 142 if (!found) break; // got unused minor 143 } 144 if (found) 145 return -EBUSY; 146 dev_info->gd->first_minor = minor; 147 return 0; 148 } 149 150 /* 151 * get the struct dcssblk_dev_info from dcssblk_devices 152 * for the given name. 153 * down_read(&dcssblk_devices_sem) must be held. 154 */ 155 static struct dcssblk_dev_info * 156 dcssblk_get_device_by_name(char *name) 157 { 158 struct dcssblk_dev_info *entry; 159 160 list_for_each_entry(entry, &dcssblk_devices, lh) { 161 if (!strcmp(name, entry->segment_name)) { 162 return entry; 163 } 164 } 165 return NULL; 166 } 167 168 /* 169 * get the struct segment_info from seg_list 170 * for the given name. 171 * down_read(&dcssblk_devices_sem) must be held. 172 */ 173 static struct segment_info * 174 dcssblk_get_segment_by_name(char *name) 175 { 176 struct dcssblk_dev_info *dev_info; 177 struct segment_info *entry; 178 179 list_for_each_entry(dev_info, &dcssblk_devices, lh) { 180 list_for_each_entry(entry, &dev_info->seg_list, lh) { 181 if (!strcmp(name, entry->segment_name)) 182 return entry; 183 } 184 } 185 return NULL; 186 } 187 188 /* 189 * get the highest address of the multi-segment block. 190 */ 191 static unsigned long 192 dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info) 193 { 194 unsigned long highest_addr; 195 struct segment_info *entry; 196 197 highest_addr = 0; 198 list_for_each_entry(entry, &dev_info->seg_list, lh) { 199 if (highest_addr < entry->end) 200 highest_addr = entry->end; 201 } 202 return highest_addr; 203 } 204 205 /* 206 * get the lowest address of the multi-segment block. 207 */ 208 static unsigned long 209 dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info) 210 { 211 int set_first; 212 unsigned long lowest_addr; 213 struct segment_info *entry; 214 215 set_first = 0; 216 lowest_addr = 0; 217 list_for_each_entry(entry, &dev_info->seg_list, lh) { 218 if (set_first == 0) { 219 lowest_addr = entry->start; 220 set_first = 1; 221 } else { 222 if (lowest_addr > entry->start) 223 lowest_addr = entry->start; 224 } 225 } 226 return lowest_addr; 227 } 228 229 /* 230 * Check continuity of segments. 231 */ 232 static int 233 dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) 234 { 235 int i, j, rc; 236 struct segment_info *sort_list, *entry, temp; 237 238 if (dev_info->num_of_segments <= 1) 239 return 0; 240 241 sort_list = kcalloc(dev_info->num_of_segments, 242 sizeof(struct segment_info), 243 GFP_KERNEL); 244 if (sort_list == NULL) 245 return -ENOMEM; 246 i = 0; 247 list_for_each_entry(entry, &dev_info->seg_list, lh) { 248 memcpy(&sort_list[i], entry, sizeof(struct segment_info)); 249 i++; 250 } 251 252 /* sort segments */ 253 for (i = 0; i < dev_info->num_of_segments; i++) 254 for (j = 0; j < dev_info->num_of_segments; j++) 255 if (sort_list[j].start > sort_list[i].start) { 256 memcpy(&temp, &sort_list[i], 257 sizeof(struct segment_info)); 258 memcpy(&sort_list[i], &sort_list[j], 259 sizeof(struct segment_info)); 260 memcpy(&sort_list[j], &temp, 261 sizeof(struct segment_info)); 262 } 263 264 /* check continuity */ 265 for (i = 0; i < dev_info->num_of_segments - 1; i++) { 266 if ((sort_list[i].end + 1) != sort_list[i+1].start) { 267 pr_err("Adjacent DCSSs %s and %s are not " 268 "contiguous\n", sort_list[i].segment_name, 269 sort_list[i+1].segment_name); 270 rc = -EINVAL; 271 goto out; 272 } 273 /* EN and EW are allowed in a block device */ 274 if (sort_list[i].segment_type != sort_list[i+1].segment_type) { 275 if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) || 276 (sort_list[i].segment_type == SEG_TYPE_ER) || 277 !(sort_list[i+1].segment_type & 278 SEGMENT_EXCLUSIVE) || 279 (sort_list[i+1].segment_type == SEG_TYPE_ER)) { 280 pr_err("DCSS %s and DCSS %s have " 281 "incompatible types\n", 282 sort_list[i].segment_name, 283 sort_list[i+1].segment_name); 284 rc = -EINVAL; 285 goto out; 286 } 287 } 288 } 289 rc = 0; 290 out: 291 kfree(sort_list); 292 return rc; 293 } 294 295 /* 296 * Load a segment 297 */ 298 static int 299 dcssblk_load_segment(char *name, struct segment_info **seg_info) 300 { 301 int rc; 302 303 /* already loaded? */ 304 down_read(&dcssblk_devices_sem); 305 *seg_info = dcssblk_get_segment_by_name(name); 306 up_read(&dcssblk_devices_sem); 307 if (*seg_info != NULL) 308 return -EEXIST; 309 310 /* get a struct segment_info */ 311 *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL); 312 if (*seg_info == NULL) 313 return -ENOMEM; 314 315 strcpy((*seg_info)->segment_name, name); 316 317 /* load the segment */ 318 rc = segment_load(name, SEGMENT_SHARED, 319 &(*seg_info)->start, &(*seg_info)->end); 320 if (rc < 0) { 321 segment_warning(rc, (*seg_info)->segment_name); 322 kfree(*seg_info); 323 } else { 324 INIT_LIST_HEAD(&(*seg_info)->lh); 325 (*seg_info)->segment_type = rc; 326 } 327 return rc; 328 } 329 330 /* 331 * device attribute for switching shared/nonshared (exclusive) 332 * operation (show + store) 333 */ 334 static ssize_t 335 dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf) 336 { 337 struct dcssblk_dev_info *dev_info; 338 339 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 340 return sprintf(buf, dev_info->is_shared ? "1\n" : "0\n"); 341 } 342 343 static ssize_t 344 dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) 345 { 346 struct dcssblk_dev_info *dev_info; 347 struct segment_info *entry, *temp; 348 int rc; 349 350 if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) 351 return -EINVAL; 352 down_write(&dcssblk_devices_sem); 353 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 354 if (atomic_read(&dev_info->use_count)) { 355 rc = -EBUSY; 356 goto out; 357 } 358 if (inbuf[0] == '1') { 359 /* reload segments in shared mode */ 360 list_for_each_entry(entry, &dev_info->seg_list, lh) { 361 rc = segment_modify_shared(entry->segment_name, 362 SEGMENT_SHARED); 363 if (rc < 0) { 364 BUG_ON(rc == -EINVAL); 365 if (rc != -EAGAIN) 366 goto removeseg; 367 } 368 } 369 dev_info->is_shared = 1; 370 switch (dev_info->segment_type) { 371 case SEG_TYPE_SR: 372 case SEG_TYPE_ER: 373 case SEG_TYPE_SC: 374 set_disk_ro(dev_info->gd, 1); 375 } 376 } else if (inbuf[0] == '0') { 377 /* reload segments in exclusive mode */ 378 if (dev_info->segment_type == SEG_TYPE_SC) { 379 pr_err("DCSS %s is of type SC and cannot be " 380 "loaded as exclusive-writable\n", 381 dev_info->segment_name); 382 rc = -EINVAL; 383 goto out; 384 } 385 list_for_each_entry(entry, &dev_info->seg_list, lh) { 386 rc = segment_modify_shared(entry->segment_name, 387 SEGMENT_EXCLUSIVE); 388 if (rc < 0) { 389 BUG_ON(rc == -EINVAL); 390 if (rc != -EAGAIN) 391 goto removeseg; 392 } 393 } 394 dev_info->is_shared = 0; 395 set_disk_ro(dev_info->gd, 0); 396 } else { 397 rc = -EINVAL; 398 goto out; 399 } 400 rc = count; 401 goto out; 402 403 removeseg: 404 pr_err("DCSS device %s is removed after a failed access mode " 405 "change\n", dev_info->segment_name); 406 temp = entry; 407 list_for_each_entry(entry, &dev_info->seg_list, lh) { 408 if (entry != temp) 409 segment_unload(entry->segment_name); 410 } 411 list_del(&dev_info->lh); 412 413 kill_dax(dev_info->dax_dev); 414 put_dax(dev_info->dax_dev); 415 del_gendisk(dev_info->gd); 416 blk_cleanup_queue(dev_info->dcssblk_queue); 417 dev_info->gd->queue = NULL; 418 put_disk(dev_info->gd); 419 up_write(&dcssblk_devices_sem); 420 421 if (device_remove_file_self(dev, attr)) { 422 device_unregister(dev); 423 put_device(dev); 424 } 425 return rc; 426 out: 427 up_write(&dcssblk_devices_sem); 428 return rc; 429 } 430 static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show, 431 dcssblk_shared_store); 432 433 /* 434 * device attribute for save operation on current copy 435 * of the segment. If the segment is busy, saving will 436 * become pending until it gets released, which can be 437 * undone by storing a non-true value to this entry. 438 * (show + store) 439 */ 440 static ssize_t 441 dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf) 442 { 443 struct dcssblk_dev_info *dev_info; 444 445 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 446 return sprintf(buf, dev_info->save_pending ? "1\n" : "0\n"); 447 } 448 449 static ssize_t 450 dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) 451 { 452 struct dcssblk_dev_info *dev_info; 453 struct segment_info *entry; 454 455 if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) 456 return -EINVAL; 457 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 458 459 down_write(&dcssblk_devices_sem); 460 if (inbuf[0] == '1') { 461 if (atomic_read(&dev_info->use_count) == 0) { 462 // device is idle => we save immediately 463 pr_info("All DCSSs that map to device %s are " 464 "saved\n", dev_info->segment_name); 465 list_for_each_entry(entry, &dev_info->seg_list, lh) { 466 if (entry->segment_type == SEG_TYPE_EN || 467 entry->segment_type == SEG_TYPE_SN) 468 pr_warn("DCSS %s is of type SN or EN" 469 " and cannot be saved\n", 470 entry->segment_name); 471 else 472 segment_save(entry->segment_name); 473 } 474 } else { 475 // device is busy => we save it when it becomes 476 // idle in dcssblk_release 477 pr_info("Device %s is in use, its DCSSs will be " 478 "saved when it becomes idle\n", 479 dev_info->segment_name); 480 dev_info->save_pending = 1; 481 } 482 } else if (inbuf[0] == '0') { 483 if (dev_info->save_pending) { 484 // device is busy & the user wants to undo his save 485 // request 486 dev_info->save_pending = 0; 487 pr_info("A pending save request for device %s " 488 "has been canceled\n", 489 dev_info->segment_name); 490 } 491 } else { 492 up_write(&dcssblk_devices_sem); 493 return -EINVAL; 494 } 495 up_write(&dcssblk_devices_sem); 496 return count; 497 } 498 static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show, 499 dcssblk_save_store); 500 501 /* 502 * device attribute for showing all segments in a device 503 */ 504 static ssize_t 505 dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, 506 char *buf) 507 { 508 int i; 509 510 struct dcssblk_dev_info *dev_info; 511 struct segment_info *entry; 512 513 down_read(&dcssblk_devices_sem); 514 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 515 i = 0; 516 buf[0] = '\0'; 517 list_for_each_entry(entry, &dev_info->seg_list, lh) { 518 strcpy(&buf[i], entry->segment_name); 519 i += strlen(entry->segment_name); 520 buf[i] = '\n'; 521 i++; 522 } 523 up_read(&dcssblk_devices_sem); 524 return i; 525 } 526 static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL); 527 528 static struct attribute *dcssblk_dev_attrs[] = { 529 &dev_attr_shared.attr, 530 &dev_attr_save.attr, 531 &dev_attr_seglist.attr, 532 NULL, 533 }; 534 static struct attribute_group dcssblk_dev_attr_group = { 535 .attrs = dcssblk_dev_attrs, 536 }; 537 static const struct attribute_group *dcssblk_dev_attr_groups[] = { 538 &dcssblk_dev_attr_group, 539 NULL, 540 }; 541 542 /* 543 * device attribute for adding devices 544 */ 545 static ssize_t 546 dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 547 { 548 int rc, i, j, num_of_segments; 549 struct dcssblk_dev_info *dev_info; 550 struct segment_info *seg_info, *temp; 551 char *local_buf; 552 unsigned long seg_byte_size; 553 554 dev_info = NULL; 555 seg_info = NULL; 556 if (dev != dcssblk_root_dev) { 557 rc = -EINVAL; 558 goto out_nobuf; 559 } 560 if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) { 561 rc = -ENAMETOOLONG; 562 goto out_nobuf; 563 } 564 565 local_buf = kmalloc(count + 1, GFP_KERNEL); 566 if (local_buf == NULL) { 567 rc = -ENOMEM; 568 goto out_nobuf; 569 } 570 571 /* 572 * parse input 573 */ 574 num_of_segments = 0; 575 for (i = 0; (i < count && (buf[i] != '\0') && (buf[i] != '\n')); i++) { 576 for (j = i; j < count && 577 (buf[j] != ':') && 578 (buf[j] != '\0') && 579 (buf[j] != '\n'); j++) { 580 local_buf[j-i] = toupper(buf[j]); 581 } 582 local_buf[j-i] = '\0'; 583 if (((j - i) == 0) || ((j - i) > 8)) { 584 rc = -ENAMETOOLONG; 585 goto seg_list_del; 586 } 587 588 rc = dcssblk_load_segment(local_buf, &seg_info); 589 if (rc < 0) 590 goto seg_list_del; 591 /* 592 * get a struct dcssblk_dev_info 593 */ 594 if (num_of_segments == 0) { 595 dev_info = kzalloc(sizeof(struct dcssblk_dev_info), 596 GFP_KERNEL); 597 if (dev_info == NULL) { 598 rc = -ENOMEM; 599 goto out; 600 } 601 strcpy(dev_info->segment_name, local_buf); 602 dev_info->segment_type = seg_info->segment_type; 603 INIT_LIST_HEAD(&dev_info->seg_list); 604 } 605 list_add_tail(&seg_info->lh, &dev_info->seg_list); 606 num_of_segments++; 607 i = j; 608 609 if ((buf[j] == '\0') || (buf[j] == '\n')) 610 break; 611 } 612 613 /* no trailing colon at the end of the input */ 614 if ((i > 0) && (buf[i-1] == ':')) { 615 rc = -ENAMETOOLONG; 616 goto seg_list_del; 617 } 618 strlcpy(local_buf, buf, i + 1); 619 dev_info->num_of_segments = num_of_segments; 620 rc = dcssblk_is_continuous(dev_info); 621 if (rc < 0) 622 goto seg_list_del; 623 624 dev_info->start = dcssblk_find_lowest_addr(dev_info); 625 dev_info->end = dcssblk_find_highest_addr(dev_info); 626 627 dev_set_name(&dev_info->dev, "%s", dev_info->segment_name); 628 dev_info->dev.release = dcssblk_release_segment; 629 dev_info->dev.groups = dcssblk_dev_attr_groups; 630 INIT_LIST_HEAD(&dev_info->lh); 631 dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); 632 if (dev_info->gd == NULL) { 633 rc = -ENOMEM; 634 goto seg_list_del; 635 } 636 dev_info->gd->major = dcssblk_major; 637 dev_info->gd->fops = &dcssblk_devops; 638 dev_info->dcssblk_queue = blk_alloc_queue(GFP_KERNEL); 639 dev_info->gd->queue = dev_info->dcssblk_queue; 640 dev_info->gd->private_data = dev_info; 641 blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); 642 blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096); 643 blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->dcssblk_queue); 644 645 seg_byte_size = (dev_info->end - dev_info->start + 1); 646 set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors 647 pr_info("Loaded %s with total size %lu bytes and capacity %lu " 648 "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9); 649 650 dev_info->save_pending = 0; 651 dev_info->is_shared = 1; 652 dev_info->dev.parent = dcssblk_root_dev; 653 654 /* 655 *get minor, add to list 656 */ 657 down_write(&dcssblk_devices_sem); 658 if (dcssblk_get_segment_by_name(local_buf)) { 659 rc = -EEXIST; 660 goto release_gd; 661 } 662 rc = dcssblk_assign_free_minor(dev_info); 663 if (rc) 664 goto release_gd; 665 sprintf(dev_info->gd->disk_name, "dcssblk%d", 666 dev_info->gd->first_minor); 667 list_add_tail(&dev_info->lh, &dcssblk_devices); 668 669 if (!try_module_get(THIS_MODULE)) { 670 rc = -ENODEV; 671 goto dev_list_del; 672 } 673 /* 674 * register the device 675 */ 676 rc = device_register(&dev_info->dev); 677 if (rc) 678 goto put_dev; 679 680 dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name, 681 &dcssblk_dax_ops); 682 if (!dev_info->dax_dev) { 683 rc = -ENOMEM; 684 goto put_dev; 685 } 686 687 get_device(&dev_info->dev); 688 device_add_disk(&dev_info->dev, dev_info->gd); 689 690 switch (dev_info->segment_type) { 691 case SEG_TYPE_SR: 692 case SEG_TYPE_ER: 693 case SEG_TYPE_SC: 694 set_disk_ro(dev_info->gd,1); 695 break; 696 default: 697 set_disk_ro(dev_info->gd,0); 698 break; 699 } 700 up_write(&dcssblk_devices_sem); 701 rc = count; 702 goto out; 703 704 put_dev: 705 list_del(&dev_info->lh); 706 blk_cleanup_queue(dev_info->dcssblk_queue); 707 dev_info->gd->queue = NULL; 708 put_disk(dev_info->gd); 709 list_for_each_entry(seg_info, &dev_info->seg_list, lh) { 710 segment_unload(seg_info->segment_name); 711 } 712 put_device(&dev_info->dev); 713 up_write(&dcssblk_devices_sem); 714 goto out; 715 dev_list_del: 716 list_del(&dev_info->lh); 717 release_gd: 718 blk_cleanup_queue(dev_info->dcssblk_queue); 719 dev_info->gd->queue = NULL; 720 put_disk(dev_info->gd); 721 up_write(&dcssblk_devices_sem); 722 seg_list_del: 723 if (dev_info == NULL) 724 goto out; 725 list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) { 726 list_del(&seg_info->lh); 727 segment_unload(seg_info->segment_name); 728 kfree(seg_info); 729 } 730 kfree(dev_info); 731 out: 732 kfree(local_buf); 733 out_nobuf: 734 return rc; 735 } 736 737 /* 738 * device attribute for removing devices 739 */ 740 static ssize_t 741 dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 742 { 743 struct dcssblk_dev_info *dev_info; 744 struct segment_info *entry; 745 int rc, i; 746 char *local_buf; 747 748 if (dev != dcssblk_root_dev) { 749 return -EINVAL; 750 } 751 local_buf = kmalloc(count + 1, GFP_KERNEL); 752 if (local_buf == NULL) { 753 return -ENOMEM; 754 } 755 /* 756 * parse input 757 */ 758 for (i = 0; (i < count && (*(buf+i)!='\0') && (*(buf+i)!='\n')); i++) { 759 local_buf[i] = toupper(buf[i]); 760 } 761 local_buf[i] = '\0'; 762 if ((i == 0) || (i > 8)) { 763 rc = -ENAMETOOLONG; 764 goto out_buf; 765 } 766 767 down_write(&dcssblk_devices_sem); 768 dev_info = dcssblk_get_device_by_name(local_buf); 769 if (dev_info == NULL) { 770 up_write(&dcssblk_devices_sem); 771 pr_warn("Device %s cannot be removed because it is not a known device\n", 772 local_buf); 773 rc = -ENODEV; 774 goto out_buf; 775 } 776 if (atomic_read(&dev_info->use_count) != 0) { 777 up_write(&dcssblk_devices_sem); 778 pr_warn("Device %s cannot be removed while it is in use\n", 779 local_buf); 780 rc = -EBUSY; 781 goto out_buf; 782 } 783 784 list_del(&dev_info->lh); 785 kill_dax(dev_info->dax_dev); 786 put_dax(dev_info->dax_dev); 787 del_gendisk(dev_info->gd); 788 blk_cleanup_queue(dev_info->dcssblk_queue); 789 dev_info->gd->queue = NULL; 790 put_disk(dev_info->gd); 791 792 /* unload all related segments */ 793 list_for_each_entry(entry, &dev_info->seg_list, lh) 794 segment_unload(entry->segment_name); 795 796 up_write(&dcssblk_devices_sem); 797 798 device_unregister(&dev_info->dev); 799 put_device(&dev_info->dev); 800 801 rc = count; 802 out_buf: 803 kfree(local_buf); 804 return rc; 805 } 806 807 static int 808 dcssblk_open(struct block_device *bdev, fmode_t mode) 809 { 810 struct dcssblk_dev_info *dev_info; 811 int rc; 812 813 dev_info = bdev->bd_disk->private_data; 814 if (NULL == dev_info) { 815 rc = -ENODEV; 816 goto out; 817 } 818 atomic_inc(&dev_info->use_count); 819 bdev->bd_block_size = 4096; 820 rc = 0; 821 out: 822 return rc; 823 } 824 825 static void 826 dcssblk_release(struct gendisk *disk, fmode_t mode) 827 { 828 struct dcssblk_dev_info *dev_info = disk->private_data; 829 struct segment_info *entry; 830 831 if (!dev_info) { 832 WARN_ON(1); 833 return; 834 } 835 down_write(&dcssblk_devices_sem); 836 if (atomic_dec_and_test(&dev_info->use_count) 837 && (dev_info->save_pending)) { 838 pr_info("Device %s has become idle and is being saved " 839 "now\n", dev_info->segment_name); 840 list_for_each_entry(entry, &dev_info->seg_list, lh) { 841 if (entry->segment_type == SEG_TYPE_EN || 842 entry->segment_type == SEG_TYPE_SN) 843 pr_warn("DCSS %s is of type SN or EN and cannot" 844 " be saved\n", entry->segment_name); 845 else 846 segment_save(entry->segment_name); 847 } 848 dev_info->save_pending = 0; 849 } 850 up_write(&dcssblk_devices_sem); 851 } 852 853 static blk_qc_t 854 dcssblk_make_request(struct request_queue *q, struct bio *bio) 855 { 856 struct dcssblk_dev_info *dev_info; 857 struct bio_vec bvec; 858 struct bvec_iter iter; 859 unsigned long index; 860 unsigned long page_addr; 861 unsigned long source_addr; 862 unsigned long bytes_done; 863 864 blk_queue_split(q, &bio); 865 866 bytes_done = 0; 867 dev_info = bio->bi_disk->private_data; 868 if (dev_info == NULL) 869 goto fail; 870 if ((bio->bi_iter.bi_sector & 7) != 0 || 871 (bio->bi_iter.bi_size & 4095) != 0) 872 /* Request is not page-aligned. */ 873 goto fail; 874 if (bio_end_sector(bio) > get_capacity(bio->bi_disk)) { 875 /* Request beyond end of DCSS segment. */ 876 goto fail; 877 } 878 /* verify data transfer direction */ 879 if (dev_info->is_shared) { 880 switch (dev_info->segment_type) { 881 case SEG_TYPE_SR: 882 case SEG_TYPE_ER: 883 case SEG_TYPE_SC: 884 /* cannot write to these segments */ 885 if (bio_data_dir(bio) == WRITE) { 886 pr_warn("Writing to %s failed because it is a read-only device\n", 887 dev_name(&dev_info->dev)); 888 goto fail; 889 } 890 } 891 } 892 893 index = (bio->bi_iter.bi_sector >> 3); 894 bio_for_each_segment(bvec, bio, iter) { 895 page_addr = (unsigned long) 896 page_address(bvec.bv_page) + bvec.bv_offset; 897 source_addr = dev_info->start + (index<<12) + bytes_done; 898 if (unlikely((page_addr & 4095) != 0) || (bvec.bv_len & 4095) != 0) 899 // More paranoia. 900 goto fail; 901 if (bio_data_dir(bio) == READ) { 902 memcpy((void*)page_addr, (void*)source_addr, 903 bvec.bv_len); 904 } else { 905 memcpy((void*)source_addr, (void*)page_addr, 906 bvec.bv_len); 907 } 908 bytes_done += bvec.bv_len; 909 } 910 bio_endio(bio); 911 return BLK_QC_T_NONE; 912 fail: 913 bio_io_error(bio); 914 return BLK_QC_T_NONE; 915 } 916 917 static long 918 __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff, 919 long nr_pages, void **kaddr, pfn_t *pfn) 920 { 921 resource_size_t offset = pgoff * PAGE_SIZE; 922 unsigned long dev_sz; 923 924 dev_sz = dev_info->end - dev_info->start + 1; 925 if (kaddr) 926 *kaddr = (void *) dev_info->start + offset; 927 if (pfn) 928 *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), 929 PFN_DEV|PFN_SPECIAL); 930 931 return (dev_sz - offset) / PAGE_SIZE; 932 } 933 934 static long 935 dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, 936 long nr_pages, void **kaddr, pfn_t *pfn) 937 { 938 struct dcssblk_dev_info *dev_info = dax_get_private(dax_dev); 939 940 return __dcssblk_direct_access(dev_info, pgoff, nr_pages, kaddr, pfn); 941 } 942 943 static void 944 dcssblk_check_params(void) 945 { 946 int rc, i, j, k; 947 char buf[DCSSBLK_PARM_LEN + 1]; 948 struct dcssblk_dev_info *dev_info; 949 950 for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); 951 i++) { 952 for (j = i; (j < DCSSBLK_PARM_LEN) && 953 (dcssblk_segments[j] != ',') && 954 (dcssblk_segments[j] != '\0') && 955 (dcssblk_segments[j] != '('); j++) 956 { 957 buf[j-i] = dcssblk_segments[j]; 958 } 959 buf[j-i] = '\0'; 960 rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); 961 if ((rc >= 0) && (dcssblk_segments[j] == '(')) { 962 for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++) 963 buf[k] = toupper(buf[k]); 964 buf[k] = '\0'; 965 if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { 966 down_read(&dcssblk_devices_sem); 967 dev_info = dcssblk_get_device_by_name(buf); 968 up_read(&dcssblk_devices_sem); 969 if (dev_info) 970 dcssblk_shared_store(&dev_info->dev, 971 NULL, "0\n", 2); 972 } 973 } 974 while ((dcssblk_segments[j] != ',') && 975 (dcssblk_segments[j] != '\0')) 976 { 977 j++; 978 } 979 if (dcssblk_segments[j] == '\0') 980 break; 981 i = j; 982 } 983 } 984 985 /* 986 * Suspend / Resume 987 */ 988 static int dcssblk_freeze(struct device *dev) 989 { 990 struct dcssblk_dev_info *dev_info; 991 int rc = 0; 992 993 list_for_each_entry(dev_info, &dcssblk_devices, lh) { 994 switch (dev_info->segment_type) { 995 case SEG_TYPE_SR: 996 case SEG_TYPE_ER: 997 case SEG_TYPE_SC: 998 if (!dev_info->is_shared) 999 rc = -EINVAL; 1000 break; 1001 default: 1002 rc = -EINVAL; 1003 break; 1004 } 1005 if (rc) 1006 break; 1007 } 1008 if (rc) 1009 pr_err("Suspending the system failed because DCSS device %s " 1010 "is writable\n", 1011 dev_info->segment_name); 1012 return rc; 1013 } 1014 1015 static int dcssblk_restore(struct device *dev) 1016 { 1017 struct dcssblk_dev_info *dev_info; 1018 struct segment_info *entry; 1019 unsigned long start, end; 1020 int rc = 0; 1021 1022 list_for_each_entry(dev_info, &dcssblk_devices, lh) { 1023 list_for_each_entry(entry, &dev_info->seg_list, lh) { 1024 segment_unload(entry->segment_name); 1025 rc = segment_load(entry->segment_name, SEGMENT_SHARED, 1026 &start, &end); 1027 if (rc < 0) { 1028 // TODO in_use check ? 1029 segment_warning(rc, entry->segment_name); 1030 goto out_panic; 1031 } 1032 if (start != entry->start || end != entry->end) { 1033 pr_err("The address range of DCSS %s changed " 1034 "while the system was suspended\n", 1035 entry->segment_name); 1036 goto out_panic; 1037 } 1038 } 1039 } 1040 return 0; 1041 out_panic: 1042 panic("fatal dcssblk resume error\n"); 1043 } 1044 1045 static int dcssblk_thaw(struct device *dev) 1046 { 1047 return 0; 1048 } 1049 1050 static const struct dev_pm_ops dcssblk_pm_ops = { 1051 .freeze = dcssblk_freeze, 1052 .thaw = dcssblk_thaw, 1053 .restore = dcssblk_restore, 1054 }; 1055 1056 static struct platform_driver dcssblk_pdrv = { 1057 .driver = { 1058 .name = "dcssblk", 1059 .pm = &dcssblk_pm_ops, 1060 }, 1061 }; 1062 1063 static struct platform_device *dcssblk_pdev; 1064 1065 1066 /* 1067 * The init/exit functions. 1068 */ 1069 static void __exit 1070 dcssblk_exit(void) 1071 { 1072 platform_device_unregister(dcssblk_pdev); 1073 platform_driver_unregister(&dcssblk_pdrv); 1074 root_device_unregister(dcssblk_root_dev); 1075 unregister_blkdev(dcssblk_major, DCSSBLK_NAME); 1076 } 1077 1078 static int __init 1079 dcssblk_init(void) 1080 { 1081 int rc; 1082 1083 rc = platform_driver_register(&dcssblk_pdrv); 1084 if (rc) 1085 return rc; 1086 1087 dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL, 1088 0); 1089 if (IS_ERR(dcssblk_pdev)) { 1090 rc = PTR_ERR(dcssblk_pdev); 1091 goto out_pdrv; 1092 } 1093 1094 dcssblk_root_dev = root_device_register("dcssblk"); 1095 if (IS_ERR(dcssblk_root_dev)) { 1096 rc = PTR_ERR(dcssblk_root_dev); 1097 goto out_pdev; 1098 } 1099 rc = device_create_file(dcssblk_root_dev, &dev_attr_add); 1100 if (rc) 1101 goto out_root; 1102 rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); 1103 if (rc) 1104 goto out_root; 1105 rc = register_blkdev(0, DCSSBLK_NAME); 1106 if (rc < 0) 1107 goto out_root; 1108 dcssblk_major = rc; 1109 init_rwsem(&dcssblk_devices_sem); 1110 1111 dcssblk_check_params(); 1112 return 0; 1113 1114 out_root: 1115 root_device_unregister(dcssblk_root_dev); 1116 out_pdev: 1117 platform_device_unregister(dcssblk_pdev); 1118 out_pdrv: 1119 platform_driver_unregister(&dcssblk_pdrv); 1120 return rc; 1121 } 1122 1123 module_init(dcssblk_init); 1124 module_exit(dcssblk_exit); 1125 1126 module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); 1127 MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " 1128 "comma-separated list, names in each set separated " 1129 "by commas are separated by colons, each set contains " 1130 "names of contiguous segments and each name max. 8 chars.\n" 1131 "Adding \"(local)\" to the end of each set equals echoing 0 " 1132 "to /sys/devices/dcssblk/<device name>/shared after loading " 1133 "the contiguous segments - \n" 1134 "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\""); 1135 1136 MODULE_LICENSE("GPL"); 1137