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