| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * nvme-lightnvm.c - LightNVM NVMe device |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2014-2015 IT University of Copenhagen |
|---|
| 5 | 6 | * Initial release: Matias Bjorling <mb@lightnvm.io> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License version |
|---|
| 9 | | - * 2 as published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 12 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 14 | | - * General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; see the file COPYING. If not, write to |
|---|
| 18 | | - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, |
|---|
| 19 | | - * USA. |
|---|
| 20 | | - * |
|---|
| 21 | 7 | */ |
|---|
| 22 | 8 | |
|---|
| 23 | 9 | #include "nvme.h" |
|---|
| .. | .. |
|---|
| 185 | 171 | __le32 tdresv; |
|---|
| 186 | 172 | __le32 thresv; |
|---|
| 187 | 173 | __le32 rsvd2[8]; |
|---|
| 188 | | - __u8 blk[0]; |
|---|
| 174 | + __u8 blk[]; |
|---|
| 189 | 175 | }; |
|---|
| 190 | 176 | |
|---|
| 191 | 177 | struct nvme_nvm_id20_addrf { |
|---|
| .. | .. |
|---|
| 567 | 553 | * Expect the lba in device format |
|---|
| 568 | 554 | */ |
|---|
| 569 | 555 | static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev, |
|---|
| 570 | | - struct nvm_chk_meta *meta, |
|---|
| 571 | | - sector_t slba, int nchks) |
|---|
| 556 | + sector_t slba, int nchks, |
|---|
| 557 | + struct nvm_chk_meta *meta) |
|---|
| 572 | 558 | { |
|---|
| 573 | 559 | struct nvm_geo *geo = &ndev->geo; |
|---|
| 574 | 560 | struct nvme_ns *ns = ndev->q->queuedata; |
|---|
| 575 | 561 | struct nvme_ctrl *ctrl = ns->ctrl; |
|---|
| 576 | | - struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta; |
|---|
| 562 | + struct nvme_nvm_chk_meta *dev_meta, *dev_meta_off; |
|---|
| 577 | 563 | struct ppa_addr ppa; |
|---|
| 578 | 564 | size_t left = nchks * sizeof(struct nvme_nvm_chk_meta); |
|---|
| 579 | 565 | size_t log_pos, offset, len; |
|---|
| 580 | | - int ret, i, max_len; |
|---|
| 566 | + int i, max_len; |
|---|
| 567 | + int ret = 0; |
|---|
| 581 | 568 | |
|---|
| 582 | 569 | /* |
|---|
| 583 | 570 | * limit requests to maximum 256K to avoid issuing arbitrary large |
|---|
| 584 | 571 | * requests when the device does not specific a maximum transfer size. |
|---|
| 585 | 572 | */ |
|---|
| 586 | 573 | max_len = min_t(unsigned int, ctrl->max_hw_sectors << 9, 256 * 1024); |
|---|
| 574 | + |
|---|
| 575 | + dev_meta = kmalloc(max_len, GFP_KERNEL); |
|---|
| 576 | + if (!dev_meta) |
|---|
| 577 | + return -ENOMEM; |
|---|
| 587 | 578 | |
|---|
| 588 | 579 | /* Normalize lba address space to obtain log offset */ |
|---|
| 589 | 580 | ppa.ppa = slba; |
|---|
| .. | .. |
|---|
| 598 | 589 | while (left) { |
|---|
| 599 | 590 | len = min_t(unsigned int, left, max_len); |
|---|
| 600 | 591 | |
|---|
| 592 | + memset(dev_meta, 0, max_len); |
|---|
| 593 | + dev_meta_off = dev_meta; |
|---|
| 594 | + |
|---|
| 601 | 595 | ret = nvme_get_log(ctrl, ns->head->ns_id, |
|---|
| 602 | | - NVME_NVM_LOG_REPORT_CHUNK, 0, dev_meta, len, |
|---|
| 603 | | - offset); |
|---|
| 596 | + NVME_NVM_LOG_REPORT_CHUNK, 0, NVME_CSI_NVM, |
|---|
| 597 | + dev_meta, len, offset); |
|---|
| 604 | 598 | if (ret) { |
|---|
| 605 | 599 | dev_err(ctrl->device, "Get REPORT CHUNK log error\n"); |
|---|
| 606 | 600 | break; |
|---|
| 607 | 601 | } |
|---|
| 608 | 602 | |
|---|
| 609 | 603 | for (i = 0; i < len; i += sizeof(struct nvme_nvm_chk_meta)) { |
|---|
| 610 | | - meta->state = dev_meta->state; |
|---|
| 611 | | - meta->type = dev_meta->type; |
|---|
| 612 | | - meta->wi = dev_meta->wi; |
|---|
| 613 | | - meta->slba = le64_to_cpu(dev_meta->slba); |
|---|
| 614 | | - meta->cnlb = le64_to_cpu(dev_meta->cnlb); |
|---|
| 615 | | - meta->wp = le64_to_cpu(dev_meta->wp); |
|---|
| 604 | + meta->state = dev_meta_off->state; |
|---|
| 605 | + meta->type = dev_meta_off->type; |
|---|
| 606 | + meta->wi = dev_meta_off->wi; |
|---|
| 607 | + meta->slba = le64_to_cpu(dev_meta_off->slba); |
|---|
| 608 | + meta->cnlb = le64_to_cpu(dev_meta_off->cnlb); |
|---|
| 609 | + meta->wp = le64_to_cpu(dev_meta_off->wp); |
|---|
| 616 | 610 | |
|---|
| 617 | 611 | meta++; |
|---|
| 618 | | - dev_meta++; |
|---|
| 612 | + dev_meta_off++; |
|---|
| 619 | 613 | } |
|---|
| 620 | 614 | |
|---|
| 621 | 615 | offset += len; |
|---|
| 622 | 616 | left -= len; |
|---|
| 623 | 617 | } |
|---|
| 618 | + |
|---|
| 619 | + kfree(dev_meta); |
|---|
| 624 | 620 | |
|---|
| 625 | 621 | return ret; |
|---|
| 626 | 622 | } |
|---|
| .. | .. |
|---|
| 657 | 653 | |
|---|
| 658 | 654 | nvme_nvm_rqtocmd(rqd, ns, cmd); |
|---|
| 659 | 655 | |
|---|
| 660 | | - rq = nvme_alloc_request(q, (struct nvme_command *)cmd, 0, NVME_QID_ANY); |
|---|
| 656 | + rq = nvme_alloc_request(q, (struct nvme_command *)cmd, 0); |
|---|
| 661 | 657 | if (IS_ERR(rq)) |
|---|
| 662 | 658 | return rq; |
|---|
| 663 | 659 | |
|---|
| 664 | 660 | rq->cmd_flags &= ~REQ_FAILFAST_DRIVER; |
|---|
| 665 | 661 | |
|---|
| 666 | 662 | if (rqd->bio) |
|---|
| 667 | | - blk_init_request_from_bio(rq, rqd->bio); |
|---|
| 663 | + blk_rq_append_bio(rq, &rqd->bio); |
|---|
| 668 | 664 | else |
|---|
| 669 | 665 | rq->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); |
|---|
| 670 | 666 | |
|---|
| 671 | 667 | return rq; |
|---|
| 672 | 668 | } |
|---|
| 673 | 669 | |
|---|
| 674 | | -static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) |
|---|
| 670 | +static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd, |
|---|
| 671 | + void *buf) |
|---|
| 675 | 672 | { |
|---|
| 673 | + struct nvm_geo *geo = &dev->geo; |
|---|
| 676 | 674 | struct request_queue *q = dev->q; |
|---|
| 677 | 675 | struct nvme_nvm_command *cmd; |
|---|
| 678 | 676 | struct request *rq; |
|---|
| 677 | + int ret; |
|---|
| 679 | 678 | |
|---|
| 680 | 679 | cmd = kzalloc(sizeof(struct nvme_nvm_command), GFP_KERNEL); |
|---|
| 681 | 680 | if (!cmd) |
|---|
| .. | .. |
|---|
| 683 | 682 | |
|---|
| 684 | 683 | rq = nvme_nvm_alloc_request(q, rqd, cmd); |
|---|
| 685 | 684 | if (IS_ERR(rq)) { |
|---|
| 686 | | - kfree(cmd); |
|---|
| 687 | | - return PTR_ERR(rq); |
|---|
| 685 | + ret = PTR_ERR(rq); |
|---|
| 686 | + goto err_free_cmd; |
|---|
| 687 | + } |
|---|
| 688 | + |
|---|
| 689 | + if (buf) { |
|---|
| 690 | + ret = blk_rq_map_kern(q, rq, buf, geo->csecs * rqd->nr_ppas, |
|---|
| 691 | + GFP_KERNEL); |
|---|
| 692 | + if (ret) |
|---|
| 693 | + goto err_free_cmd; |
|---|
| 688 | 694 | } |
|---|
| 689 | 695 | |
|---|
| 690 | 696 | rq->end_io_data = rqd; |
|---|
| .. | .. |
|---|
| 692 | 698 | blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_io); |
|---|
| 693 | 699 | |
|---|
| 694 | 700 | return 0; |
|---|
| 695 | | -} |
|---|
| 696 | 701 | |
|---|
| 697 | | -static int nvme_nvm_submit_io_sync(struct nvm_dev *dev, struct nvm_rq *rqd) |
|---|
| 698 | | -{ |
|---|
| 699 | | - struct request_queue *q = dev->q; |
|---|
| 700 | | - struct request *rq; |
|---|
| 701 | | - struct nvme_nvm_command cmd; |
|---|
| 702 | | - int ret = 0; |
|---|
| 703 | | - |
|---|
| 704 | | - memset(&cmd, 0, sizeof(struct nvme_nvm_command)); |
|---|
| 705 | | - |
|---|
| 706 | | - rq = nvme_nvm_alloc_request(q, rqd, &cmd); |
|---|
| 707 | | - if (IS_ERR(rq)) |
|---|
| 708 | | - return PTR_ERR(rq); |
|---|
| 709 | | - |
|---|
| 710 | | - /* I/Os can fail and the error is signaled through rqd. Callers must |
|---|
| 711 | | - * handle the error accordingly. |
|---|
| 712 | | - */ |
|---|
| 713 | | - blk_execute_rq(q, NULL, rq, 0); |
|---|
| 714 | | - if (nvme_req(rq)->flags & NVME_REQ_CANCELLED) |
|---|
| 715 | | - ret = -EINTR; |
|---|
| 716 | | - |
|---|
| 717 | | - rqd->ppa_status = le64_to_cpu(nvme_req(rq)->result.u64); |
|---|
| 718 | | - rqd->error = nvme_req(rq)->status; |
|---|
| 719 | | - |
|---|
| 720 | | - blk_mq_free_request(rq); |
|---|
| 721 | | - |
|---|
| 702 | +err_free_cmd: |
|---|
| 703 | + kfree(cmd); |
|---|
| 722 | 704 | return ret; |
|---|
| 723 | 705 | } |
|---|
| 724 | 706 | |
|---|
| 725 | | -static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name) |
|---|
| 707 | +static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name, |
|---|
| 708 | + int size) |
|---|
| 726 | 709 | { |
|---|
| 727 | 710 | struct nvme_ns *ns = nvmdev->q->queuedata; |
|---|
| 728 | 711 | |
|---|
| 729 | | - return dma_pool_create(name, ns->ctrl->dev, PAGE_SIZE, PAGE_SIZE, 0); |
|---|
| 712 | + return dma_pool_create(name, ns->ctrl->dev, size, PAGE_SIZE, 0); |
|---|
| 730 | 713 | } |
|---|
| 731 | 714 | |
|---|
| 732 | 715 | static void nvme_nvm_destroy_dma_pool(void *pool) |
|---|
| .. | .. |
|---|
| 757 | 740 | .get_chk_meta = nvme_nvm_get_chk_meta, |
|---|
| 758 | 741 | |
|---|
| 759 | 742 | .submit_io = nvme_nvm_submit_io, |
|---|
| 760 | | - .submit_io_sync = nvme_nvm_submit_io_sync, |
|---|
| 761 | 743 | |
|---|
| 762 | 744 | .create_dma_pool = nvme_nvm_create_dma_pool, |
|---|
| 763 | 745 | .destroy_dma_pool = nvme_nvm_destroy_dma_pool, |
|---|
| .. | .. |
|---|
| 785 | 767 | DECLARE_COMPLETION_ONSTACK(wait); |
|---|
| 786 | 768 | int ret = 0; |
|---|
| 787 | 769 | |
|---|
| 788 | | - rq = nvme_alloc_request(q, (struct nvme_command *)vcmd, 0, |
|---|
| 789 | | - NVME_QID_ANY); |
|---|
| 770 | + rq = nvme_alloc_request(q, (struct nvme_command *)vcmd, 0); |
|---|
| 790 | 771 | if (IS_ERR(rq)) { |
|---|
| 791 | 772 | ret = -ENOMEM; |
|---|
| 792 | 773 | goto err_cmd; |
|---|
| 793 | 774 | } |
|---|
| 794 | 775 | |
|---|
| 795 | | - rq->timeout = timeout ? timeout : ADMIN_TIMEOUT; |
|---|
| 776 | + if (timeout) |
|---|
| 777 | + rq->timeout = timeout; |
|---|
| 796 | 778 | |
|---|
| 797 | 779 | if (ppa_buf && ppa_len) { |
|---|
| 798 | 780 | ppa_list = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, &ppa_dma); |
|---|
| .. | .. |
|---|
| 926 | 908 | /* cdw11-12 */ |
|---|
| 927 | 909 | c.ph_rw.length = cpu_to_le16(vcmd.nppas); |
|---|
| 928 | 910 | c.ph_rw.control = cpu_to_le16(vcmd.control); |
|---|
| 929 | | - c.common.cdw10[3] = cpu_to_le32(vcmd.cdw13); |
|---|
| 930 | | - c.common.cdw10[4] = cpu_to_le32(vcmd.cdw14); |
|---|
| 931 | | - c.common.cdw10[5] = cpu_to_le32(vcmd.cdw15); |
|---|
| 911 | + c.common.cdw13 = cpu_to_le32(vcmd.cdw13); |
|---|
| 912 | + c.common.cdw14 = cpu_to_le32(vcmd.cdw14); |
|---|
| 913 | + c.common.cdw15 = cpu_to_le32(vcmd.cdw15); |
|---|
| 932 | 914 | |
|---|
| 933 | 915 | if (vcmd.timeout_ms) |
|---|
| 934 | 916 | timeout = msecs_to_jiffies(vcmd.timeout_ms); |
|---|
| .. | .. |
|---|
| 963 | 945 | } |
|---|
| 964 | 946 | } |
|---|
| 965 | 947 | |
|---|
| 966 | | -void nvme_nvm_update_nvm_info(struct nvme_ns *ns) |
|---|
| 967 | | -{ |
|---|
| 968 | | - struct nvm_dev *ndev = ns->ndev; |
|---|
| 969 | | - struct nvm_geo *geo = &ndev->geo; |
|---|
| 970 | | - |
|---|
| 971 | | - if (geo->version == NVM_OCSSD_SPEC_12) |
|---|
| 972 | | - return; |
|---|
| 973 | | - |
|---|
| 974 | | - geo->csecs = 1 << ns->lba_shift; |
|---|
| 975 | | - geo->sos = ns->ms; |
|---|
| 976 | | -} |
|---|
| 977 | | - |
|---|
| 978 | 948 | int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node) |
|---|
| 979 | 949 | { |
|---|
| 980 | 950 | struct request_queue *q = ns->queue; |
|---|
| 981 | 951 | struct nvm_dev *dev; |
|---|
| 952 | + struct nvm_geo *geo; |
|---|
| 982 | 953 | |
|---|
| 983 | 954 | _nvme_nvm_check_size(); |
|---|
| 984 | 955 | |
|---|
| 985 | 956 | dev = nvm_alloc_dev(node); |
|---|
| 986 | 957 | if (!dev) |
|---|
| 987 | 958 | return -ENOMEM; |
|---|
| 959 | + |
|---|
| 960 | + /* Note that csecs and sos will be overridden if it is a 1.2 drive. */ |
|---|
| 961 | + geo = &dev->geo; |
|---|
| 962 | + geo->csecs = 1 << ns->lba_shift; |
|---|
| 963 | + geo->sos = ns->ms; |
|---|
| 964 | + if (ns->features & NVME_NS_EXT_LBAS) |
|---|
| 965 | + geo->ext = true; |
|---|
| 966 | + else |
|---|
| 967 | + geo->ext = false; |
|---|
| 968 | + geo->mdts = ns->ctrl->max_hw_sectors; |
|---|
| 988 | 969 | |
|---|
| 989 | 970 | dev->q = q; |
|---|
| 990 | 971 | memcpy(dev->name, disk_name, DISK_NAME_LEN); |
|---|
| .. | .. |
|---|
| 1193 | 1174 | static NVM_DEV_ATTR_12_RO(media_capabilities); |
|---|
| 1194 | 1175 | static NVM_DEV_ATTR_12_RO(max_phys_secs); |
|---|
| 1195 | 1176 | |
|---|
| 1196 | | -static struct attribute *nvm_dev_attrs_12[] = { |
|---|
| 1197 | | - &dev_attr_version.attr, |
|---|
| 1198 | | - &dev_attr_capabilities.attr, |
|---|
| 1199 | | - |
|---|
| 1200 | | - &dev_attr_vendor_opcode.attr, |
|---|
| 1201 | | - &dev_attr_device_mode.attr, |
|---|
| 1202 | | - &dev_attr_media_manager.attr, |
|---|
| 1203 | | - &dev_attr_ppa_format.attr, |
|---|
| 1204 | | - &dev_attr_media_type.attr, |
|---|
| 1205 | | - &dev_attr_flash_media_type.attr, |
|---|
| 1206 | | - &dev_attr_num_channels.attr, |
|---|
| 1207 | | - &dev_attr_num_luns.attr, |
|---|
| 1208 | | - &dev_attr_num_planes.attr, |
|---|
| 1209 | | - &dev_attr_num_blocks.attr, |
|---|
| 1210 | | - &dev_attr_num_pages.attr, |
|---|
| 1211 | | - &dev_attr_page_size.attr, |
|---|
| 1212 | | - &dev_attr_hw_sector_size.attr, |
|---|
| 1213 | | - &dev_attr_oob_sector_size.attr, |
|---|
| 1214 | | - &dev_attr_read_typ.attr, |
|---|
| 1215 | | - &dev_attr_read_max.attr, |
|---|
| 1216 | | - &dev_attr_prog_typ.attr, |
|---|
| 1217 | | - &dev_attr_prog_max.attr, |
|---|
| 1218 | | - &dev_attr_erase_typ.attr, |
|---|
| 1219 | | - &dev_attr_erase_max.attr, |
|---|
| 1220 | | - &dev_attr_multiplane_modes.attr, |
|---|
| 1221 | | - &dev_attr_media_capabilities.attr, |
|---|
| 1222 | | - &dev_attr_max_phys_secs.attr, |
|---|
| 1223 | | - |
|---|
| 1224 | | - NULL, |
|---|
| 1225 | | -}; |
|---|
| 1226 | | - |
|---|
| 1227 | | -static const struct attribute_group nvm_dev_attr_group_12 = { |
|---|
| 1228 | | - .name = "lightnvm", |
|---|
| 1229 | | - .attrs = nvm_dev_attrs_12, |
|---|
| 1230 | | -}; |
|---|
| 1231 | | - |
|---|
| 1232 | 1177 | /* 2.0 values */ |
|---|
| 1233 | 1178 | static NVM_DEV_ATTR_20_RO(groups); |
|---|
| 1234 | 1179 | static NVM_DEV_ATTR_20_RO(punits); |
|---|
| .. | .. |
|---|
| 1244 | 1189 | static NVM_DEV_ATTR_20_RO(reset_typ); |
|---|
| 1245 | 1190 | static NVM_DEV_ATTR_20_RO(reset_max); |
|---|
| 1246 | 1191 | |
|---|
| 1247 | | -static struct attribute *nvm_dev_attrs_20[] = { |
|---|
| 1192 | +static struct attribute *nvm_dev_attrs[] = { |
|---|
| 1193 | + /* version agnostic attrs */ |
|---|
| 1248 | 1194 | &dev_attr_version.attr, |
|---|
| 1249 | 1195 | &dev_attr_capabilities.attr, |
|---|
| 1196 | + &dev_attr_read_typ.attr, |
|---|
| 1197 | + &dev_attr_read_max.attr, |
|---|
| 1250 | 1198 | |
|---|
| 1199 | + /* 1.2 attrs */ |
|---|
| 1200 | + &dev_attr_vendor_opcode.attr, |
|---|
| 1201 | + &dev_attr_device_mode.attr, |
|---|
| 1202 | + &dev_attr_media_manager.attr, |
|---|
| 1203 | + &dev_attr_ppa_format.attr, |
|---|
| 1204 | + &dev_attr_media_type.attr, |
|---|
| 1205 | + &dev_attr_flash_media_type.attr, |
|---|
| 1206 | + &dev_attr_num_channels.attr, |
|---|
| 1207 | + &dev_attr_num_luns.attr, |
|---|
| 1208 | + &dev_attr_num_planes.attr, |
|---|
| 1209 | + &dev_attr_num_blocks.attr, |
|---|
| 1210 | + &dev_attr_num_pages.attr, |
|---|
| 1211 | + &dev_attr_page_size.attr, |
|---|
| 1212 | + &dev_attr_hw_sector_size.attr, |
|---|
| 1213 | + &dev_attr_oob_sector_size.attr, |
|---|
| 1214 | + &dev_attr_prog_typ.attr, |
|---|
| 1215 | + &dev_attr_prog_max.attr, |
|---|
| 1216 | + &dev_attr_erase_typ.attr, |
|---|
| 1217 | + &dev_attr_erase_max.attr, |
|---|
| 1218 | + &dev_attr_multiplane_modes.attr, |
|---|
| 1219 | + &dev_attr_media_capabilities.attr, |
|---|
| 1220 | + &dev_attr_max_phys_secs.attr, |
|---|
| 1221 | + |
|---|
| 1222 | + /* 2.0 attrs */ |
|---|
| 1251 | 1223 | &dev_attr_groups.attr, |
|---|
| 1252 | 1224 | &dev_attr_punits.attr, |
|---|
| 1253 | 1225 | &dev_attr_chunks.attr, |
|---|
| .. | .. |
|---|
| 1258 | 1230 | &dev_attr_maxocpu.attr, |
|---|
| 1259 | 1231 | &dev_attr_mw_cunits.attr, |
|---|
| 1260 | 1232 | |
|---|
| 1261 | | - &dev_attr_read_typ.attr, |
|---|
| 1262 | | - &dev_attr_read_max.attr, |
|---|
| 1263 | 1233 | &dev_attr_write_typ.attr, |
|---|
| 1264 | 1234 | &dev_attr_write_max.attr, |
|---|
| 1265 | 1235 | &dev_attr_reset_typ.attr, |
|---|
| .. | .. |
|---|
| 1268 | 1238 | NULL, |
|---|
| 1269 | 1239 | }; |
|---|
| 1270 | 1240 | |
|---|
| 1271 | | -static const struct attribute_group nvm_dev_attr_group_20 = { |
|---|
| 1272 | | - .name = "lightnvm", |
|---|
| 1273 | | - .attrs = nvm_dev_attrs_20, |
|---|
| 1274 | | -}; |
|---|
| 1275 | | - |
|---|
| 1276 | | -int nvme_nvm_register_sysfs(struct nvme_ns *ns) |
|---|
| 1241 | +static umode_t nvm_dev_attrs_visible(struct kobject *kobj, |
|---|
| 1242 | + struct attribute *attr, int index) |
|---|
| 1277 | 1243 | { |
|---|
| 1244 | + struct device *dev = container_of(kobj, struct device, kobj); |
|---|
| 1245 | + struct gendisk *disk = dev_to_disk(dev); |
|---|
| 1246 | + struct nvme_ns *ns = disk->private_data; |
|---|
| 1278 | 1247 | struct nvm_dev *ndev = ns->ndev; |
|---|
| 1279 | | - struct nvm_geo *geo = &ndev->geo; |
|---|
| 1248 | + struct device_attribute *dev_attr = |
|---|
| 1249 | + container_of(attr, typeof(*dev_attr), attr); |
|---|
| 1280 | 1250 | |
|---|
| 1281 | 1251 | if (!ndev) |
|---|
| 1282 | | - return -EINVAL; |
|---|
| 1252 | + return 0; |
|---|
| 1283 | 1253 | |
|---|
| 1284 | | - switch (geo->major_ver_id) { |
|---|
| 1254 | + if (dev_attr->show == nvm_dev_attr_show) |
|---|
| 1255 | + return attr->mode; |
|---|
| 1256 | + |
|---|
| 1257 | + switch (ndev->geo.major_ver_id) { |
|---|
| 1285 | 1258 | case 1: |
|---|
| 1286 | | - return sysfs_create_group(&disk_to_dev(ns->disk)->kobj, |
|---|
| 1287 | | - &nvm_dev_attr_group_12); |
|---|
| 1288 | | - case 2: |
|---|
| 1289 | | - return sysfs_create_group(&disk_to_dev(ns->disk)->kobj, |
|---|
| 1290 | | - &nvm_dev_attr_group_20); |
|---|
| 1291 | | - } |
|---|
| 1292 | | - |
|---|
| 1293 | | - return -EINVAL; |
|---|
| 1294 | | -} |
|---|
| 1295 | | - |
|---|
| 1296 | | -void nvme_nvm_unregister_sysfs(struct nvme_ns *ns) |
|---|
| 1297 | | -{ |
|---|
| 1298 | | - struct nvm_dev *ndev = ns->ndev; |
|---|
| 1299 | | - struct nvm_geo *geo = &ndev->geo; |
|---|
| 1300 | | - |
|---|
| 1301 | | - switch (geo->major_ver_id) { |
|---|
| 1302 | | - case 1: |
|---|
| 1303 | | - sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, |
|---|
| 1304 | | - &nvm_dev_attr_group_12); |
|---|
| 1259 | + if (dev_attr->show == nvm_dev_attr_show_12) |
|---|
| 1260 | + return attr->mode; |
|---|
| 1305 | 1261 | break; |
|---|
| 1306 | 1262 | case 2: |
|---|
| 1307 | | - sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, |
|---|
| 1308 | | - &nvm_dev_attr_group_20); |
|---|
| 1263 | + if (dev_attr->show == nvm_dev_attr_show_20) |
|---|
| 1264 | + return attr->mode; |
|---|
| 1309 | 1265 | break; |
|---|
| 1310 | 1266 | } |
|---|
| 1267 | + |
|---|
| 1268 | + return 0; |
|---|
| 1311 | 1269 | } |
|---|
| 1270 | + |
|---|
| 1271 | +const struct attribute_group nvme_nvm_attr_group = { |
|---|
| 1272 | + .name = "lightnvm", |
|---|
| 1273 | + .attrs = nvm_dev_attrs, |
|---|
| 1274 | + .is_visible = nvm_dev_attrs_visible, |
|---|
| 1275 | +}; |
|---|