14a826c83SDan Williams /* 24a826c83SDan Williams * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. 34a826c83SDan Williams * 44a826c83SDan Williams * This program is free software; you can redistribute it and/or modify 54a826c83SDan Williams * it under the terms of version 2 of the GNU General Public License as 64a826c83SDan Williams * published by the Free Software Foundation. 74a826c83SDan Williams * 84a826c83SDan Williams * This program is distributed in the hope that it will be useful, but 94a826c83SDan Williams * WITHOUT ANY WARRANTY; without even the implied warranty of 104a826c83SDan Williams * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 114a826c83SDan Williams * General Public License for more details. 124a826c83SDan Williams */ 134a826c83SDan Williams #include <linux/device.h> 144a826c83SDan Williams #include <linux/ndctl.h> 154a826c83SDan Williams #include <linux/io.h> 164a826c83SDan Williams #include <linux/nd.h> 174a826c83SDan Williams #include "nd-core.h" 184a826c83SDan Williams #include "label.h" 194a826c83SDan Williams #include "nd.h" 204a826c83SDan Williams 214a826c83SDan Williams static u32 best_seq(u32 a, u32 b) 224a826c83SDan Williams { 234a826c83SDan Williams a &= NSINDEX_SEQ_MASK; 244a826c83SDan Williams b &= NSINDEX_SEQ_MASK; 254a826c83SDan Williams 264a826c83SDan Williams if (a == 0 || a == b) 274a826c83SDan Williams return b; 284a826c83SDan Williams else if (b == 0) 294a826c83SDan Williams return a; 304a826c83SDan Williams else if (nd_inc_seq(a) == b) 314a826c83SDan Williams return b; 324a826c83SDan Williams else 334a826c83SDan Williams return a; 344a826c83SDan Williams } 354a826c83SDan Williams 364a826c83SDan Williams size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd) 374a826c83SDan Williams { 384a826c83SDan Williams u32 index_span; 394a826c83SDan Williams 404a826c83SDan Williams if (ndd->nsindex_size) 414a826c83SDan Williams return ndd->nsindex_size; 424a826c83SDan Williams 434a826c83SDan Williams /* 444a826c83SDan Williams * The minimum index space is 512 bytes, with that amount of 454a826c83SDan Williams * index we can describe ~1400 labels which is less than a byte 464a826c83SDan Williams * of overhead per label. Round up to a byte of overhead per 474a826c83SDan Williams * label and determine the size of the index region. Yes, this 484a826c83SDan Williams * starts to waste space at larger config_sizes, but it's 494a826c83SDan Williams * unlikely we'll ever see anything but 128K. 504a826c83SDan Williams */ 514a826c83SDan Williams index_span = ndd->nsarea.config_size / 129; 524a826c83SDan Williams index_span /= NSINDEX_ALIGN * 2; 534a826c83SDan Williams ndd->nsindex_size = index_span * NSINDEX_ALIGN; 544a826c83SDan Williams 554a826c83SDan Williams return ndd->nsindex_size; 564a826c83SDan Williams } 574a826c83SDan Williams 584a826c83SDan Williams int nd_label_validate(struct nvdimm_drvdata *ndd) 594a826c83SDan Williams { 604a826c83SDan Williams /* 614a826c83SDan Williams * On media label format consists of two index blocks followed 624a826c83SDan Williams * by an array of labels. None of these structures are ever 634a826c83SDan Williams * updated in place. A sequence number tracks the current 644a826c83SDan Williams * active index and the next one to write, while labels are 654a826c83SDan Williams * written to free slots. 664a826c83SDan Williams * 674a826c83SDan Williams * +------------+ 684a826c83SDan Williams * | | 694a826c83SDan Williams * | nsindex0 | 704a826c83SDan Williams * | | 714a826c83SDan Williams * +------------+ 724a826c83SDan Williams * | | 734a826c83SDan Williams * | nsindex1 | 744a826c83SDan Williams * | | 754a826c83SDan Williams * +------------+ 764a826c83SDan Williams * | label0 | 774a826c83SDan Williams * +------------+ 784a826c83SDan Williams * | label1 | 794a826c83SDan Williams * +------------+ 804a826c83SDan Williams * | | 814a826c83SDan Williams * ....nslot... 824a826c83SDan Williams * | | 834a826c83SDan Williams * +------------+ 844a826c83SDan Williams * | labelN | 854a826c83SDan Williams * +------------+ 864a826c83SDan Williams */ 874a826c83SDan Williams struct nd_namespace_index *nsindex[] = { 884a826c83SDan Williams to_namespace_index(ndd, 0), 894a826c83SDan Williams to_namespace_index(ndd, 1), 904a826c83SDan Williams }; 914a826c83SDan Williams const int num_index = ARRAY_SIZE(nsindex); 924a826c83SDan Williams struct device *dev = ndd->dev; 934a826c83SDan Williams bool valid[2] = { 0 }; 944a826c83SDan Williams int i, num_valid = 0; 954a826c83SDan Williams u32 seq; 964a826c83SDan Williams 974a826c83SDan Williams for (i = 0; i < num_index; i++) { 984a826c83SDan Williams u32 nslot; 994a826c83SDan Williams u8 sig[NSINDEX_SIG_LEN]; 1004a826c83SDan Williams u64 sum_save, sum, size; 1014a826c83SDan Williams 1024a826c83SDan Williams memcpy(sig, nsindex[i]->sig, NSINDEX_SIG_LEN); 1034a826c83SDan Williams if (memcmp(sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN) != 0) { 1044a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d signature invalid\n", 1054a826c83SDan Williams __func__, i); 1064a826c83SDan Williams continue; 1074a826c83SDan Williams } 1084a826c83SDan Williams sum_save = __le64_to_cpu(nsindex[i]->checksum); 1094a826c83SDan Williams nsindex[i]->checksum = __cpu_to_le64(0); 1104a826c83SDan Williams sum = nd_fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1); 1114a826c83SDan Williams nsindex[i]->checksum = __cpu_to_le64(sum_save); 1124a826c83SDan Williams if (sum != sum_save) { 1134a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d checksum invalid\n", 1144a826c83SDan Williams __func__, i); 1154a826c83SDan Williams continue; 1164a826c83SDan Williams } 1174a826c83SDan Williams 1184a826c83SDan Williams seq = __le32_to_cpu(nsindex[i]->seq); 1194a826c83SDan Williams if ((seq & NSINDEX_SEQ_MASK) == 0) { 1204a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d sequence: %#x invalid\n", 1214a826c83SDan Williams __func__, i, seq); 1224a826c83SDan Williams continue; 1234a826c83SDan Williams } 1244a826c83SDan Williams 1254a826c83SDan Williams /* sanity check the index against expected values */ 1264a826c83SDan Williams if (__le64_to_cpu(nsindex[i]->myoff) 1274a826c83SDan Williams != i * sizeof_namespace_index(ndd)) { 1284a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d myoff: %#llx invalid\n", 1294a826c83SDan Williams __func__, i, (unsigned long long) 1304a826c83SDan Williams __le64_to_cpu(nsindex[i]->myoff)); 1314a826c83SDan Williams continue; 1324a826c83SDan Williams } 1334a826c83SDan Williams if (__le64_to_cpu(nsindex[i]->otheroff) 1344a826c83SDan Williams != (!i) * sizeof_namespace_index(ndd)) { 1354a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d otheroff: %#llx invalid\n", 1364a826c83SDan Williams __func__, i, (unsigned long long) 1374a826c83SDan Williams __le64_to_cpu(nsindex[i]->otheroff)); 1384a826c83SDan Williams continue; 1394a826c83SDan Williams } 1404a826c83SDan Williams 1414a826c83SDan Williams size = __le64_to_cpu(nsindex[i]->mysize); 1424a826c83SDan Williams if (size > sizeof_namespace_index(ndd) 1434a826c83SDan Williams || size < sizeof(struct nd_namespace_index)) { 1444a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d mysize: %#llx invalid\n", 1454a826c83SDan Williams __func__, i, size); 1464a826c83SDan Williams continue; 1474a826c83SDan Williams } 1484a826c83SDan Williams 1494a826c83SDan Williams nslot = __le32_to_cpu(nsindex[i]->nslot); 1504a826c83SDan Williams if (nslot * sizeof(struct nd_namespace_label) 1514a826c83SDan Williams + 2 * sizeof_namespace_index(ndd) 1524a826c83SDan Williams > ndd->nsarea.config_size) { 1534a826c83SDan Williams dev_dbg(dev, "%s: nsindex%d nslot: %u invalid, config_size: %#x\n", 1544a826c83SDan Williams __func__, i, nslot, 1554a826c83SDan Williams ndd->nsarea.config_size); 1564a826c83SDan Williams continue; 1574a826c83SDan Williams } 1584a826c83SDan Williams valid[i] = true; 1594a826c83SDan Williams num_valid++; 1604a826c83SDan Williams } 1614a826c83SDan Williams 1624a826c83SDan Williams switch (num_valid) { 1634a826c83SDan Williams case 0: 1644a826c83SDan Williams break; 1654a826c83SDan Williams case 1: 1664a826c83SDan Williams for (i = 0; i < num_index; i++) 1674a826c83SDan Williams if (valid[i]) 1684a826c83SDan Williams return i; 1694a826c83SDan Williams /* can't have num_valid > 0 but valid[] = { false, false } */ 1704a826c83SDan Williams WARN_ON(1); 1714a826c83SDan Williams break; 1724a826c83SDan Williams default: 1734a826c83SDan Williams /* pick the best index... */ 1744a826c83SDan Williams seq = best_seq(__le32_to_cpu(nsindex[0]->seq), 1754a826c83SDan Williams __le32_to_cpu(nsindex[1]->seq)); 1764a826c83SDan Williams if (seq == (__le32_to_cpu(nsindex[1]->seq) & NSINDEX_SEQ_MASK)) 1774a826c83SDan Williams return 1; 1784a826c83SDan Williams else 1794a826c83SDan Williams return 0; 1804a826c83SDan Williams break; 1814a826c83SDan Williams } 1824a826c83SDan Williams 1834a826c83SDan Williams return -1; 1844a826c83SDan Williams } 1854a826c83SDan Williams 1864a826c83SDan Williams void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst, 1874a826c83SDan Williams struct nd_namespace_index *src) 1884a826c83SDan Williams { 1894a826c83SDan Williams if (dst && src) 1904a826c83SDan Williams /* pass */; 1914a826c83SDan Williams else 1924a826c83SDan Williams return; 1934a826c83SDan Williams 1944a826c83SDan Williams memcpy(dst, src, sizeof_namespace_index(ndd)); 1954a826c83SDan Williams } 1964a826c83SDan Williams 1974a826c83SDan Williams static struct nd_namespace_label *nd_label_base(struct nvdimm_drvdata *ndd) 1984a826c83SDan Williams { 1994a826c83SDan Williams void *base = to_namespace_index(ndd, 0); 2004a826c83SDan Williams 2014a826c83SDan Williams return base + 2 * sizeof_namespace_index(ndd); 2024a826c83SDan Williams } 2034a826c83SDan Williams 2044a826c83SDan Williams #define for_each_clear_bit_le(bit, addr, size) \ 2054a826c83SDan Williams for ((bit) = find_next_zero_bit_le((addr), (size), 0); \ 2064a826c83SDan Williams (bit) < (size); \ 2074a826c83SDan Williams (bit) = find_next_zero_bit_le((addr), (size), (bit) + 1)) 2084a826c83SDan Williams 2094a826c83SDan Williams /** 2104a826c83SDan Williams * preamble_current - common variable initialization for nd_label_* routines 2114a826c83SDan Williams * @ndd: dimm container for the relevant label set 2124a826c83SDan Williams * @nsindex_out: on return set to the currently active namespace index 2134a826c83SDan Williams * @free: on return set to the free label bitmap in the index 2144a826c83SDan Williams * @nslot: on return set to the number of slots in the label space 2154a826c83SDan Williams */ 2164a826c83SDan Williams static bool preamble_current(struct nvdimm_drvdata *ndd, 2174a826c83SDan Williams struct nd_namespace_index **nsindex_out, 2184a826c83SDan Williams unsigned long **free, u32 *nslot) 2194a826c83SDan Williams { 2204a826c83SDan Williams struct nd_namespace_index *nsindex; 2214a826c83SDan Williams 2224a826c83SDan Williams nsindex = to_current_namespace_index(ndd); 2234a826c83SDan Williams if (nsindex == NULL) 2244a826c83SDan Williams return false; 2254a826c83SDan Williams 2264a826c83SDan Williams *free = (unsigned long *) nsindex->free; 2274a826c83SDan Williams *nslot = __le32_to_cpu(nsindex->nslot); 2284a826c83SDan Williams *nsindex_out = nsindex; 2294a826c83SDan Williams 2304a826c83SDan Williams return true; 2314a826c83SDan Williams } 2324a826c83SDan Williams 233*bf9bccc1SDan Williams char *nd_label_gen_id(struct nd_label_id *label_id, u8 *uuid, u32 flags) 2344a826c83SDan Williams { 2354a826c83SDan Williams if (!label_id || !uuid) 2364a826c83SDan Williams return NULL; 2374a826c83SDan Williams snprintf(label_id->id, ND_LABEL_ID_SIZE, "%s-%pUb", 2384a826c83SDan Williams flags & NSLABEL_FLAG_LOCAL ? "blk" : "pmem", uuid); 2394a826c83SDan Williams return label_id->id; 2404a826c83SDan Williams } 2414a826c83SDan Williams 2424a826c83SDan Williams static bool slot_valid(struct nd_namespace_label *nd_label, u32 slot) 2434a826c83SDan Williams { 2444a826c83SDan Williams /* check that we are written where we expect to be written */ 2454a826c83SDan Williams if (slot != __le32_to_cpu(nd_label->slot)) 2464a826c83SDan Williams return false; 2474a826c83SDan Williams 2484a826c83SDan Williams /* check that DPA allocations are page aligned */ 2494a826c83SDan Williams if ((__le64_to_cpu(nd_label->dpa) 2504a826c83SDan Williams | __le64_to_cpu(nd_label->rawsize)) % SZ_4K) 2514a826c83SDan Williams return false; 2524a826c83SDan Williams 2534a826c83SDan Williams return true; 2544a826c83SDan Williams } 2554a826c83SDan Williams 2564a826c83SDan Williams int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) 2574a826c83SDan Williams { 2584a826c83SDan Williams struct nd_namespace_index *nsindex; 2594a826c83SDan Williams unsigned long *free; 2604a826c83SDan Williams u32 nslot, slot; 2614a826c83SDan Williams 2624a826c83SDan Williams if (!preamble_current(ndd, &nsindex, &free, &nslot)) 2634a826c83SDan Williams return 0; /* no label, nothing to reserve */ 2644a826c83SDan Williams 2654a826c83SDan Williams for_each_clear_bit_le(slot, free, nslot) { 2664a826c83SDan Williams struct nd_namespace_label *nd_label; 2674a826c83SDan Williams struct nd_region *nd_region = NULL; 2684a826c83SDan Williams u8 label_uuid[NSLABEL_UUID_LEN]; 2694a826c83SDan Williams struct nd_label_id label_id; 2704a826c83SDan Williams struct resource *res; 2714a826c83SDan Williams u32 flags; 2724a826c83SDan Williams 2734a826c83SDan Williams nd_label = nd_label_base(ndd) + slot; 2744a826c83SDan Williams 2754a826c83SDan Williams if (!slot_valid(nd_label, slot)) 2764a826c83SDan Williams continue; 2774a826c83SDan Williams 2784a826c83SDan Williams memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); 2794a826c83SDan Williams flags = __le32_to_cpu(nd_label->flags); 2804a826c83SDan Williams nd_label_gen_id(&label_id, label_uuid, flags); 2814a826c83SDan Williams res = nvdimm_allocate_dpa(ndd, &label_id, 2824a826c83SDan Williams __le64_to_cpu(nd_label->dpa), 2834a826c83SDan Williams __le64_to_cpu(nd_label->rawsize)); 2844a826c83SDan Williams nd_dbg_dpa(nd_region, ndd, res, "reserve\n"); 2854a826c83SDan Williams if (!res) 2864a826c83SDan Williams return -EBUSY; 2874a826c83SDan Williams } 2884a826c83SDan Williams 2894a826c83SDan Williams return 0; 2904a826c83SDan Williams } 291*bf9bccc1SDan Williams 292*bf9bccc1SDan Williams int nd_label_active_count(struct nvdimm_drvdata *ndd) 293*bf9bccc1SDan Williams { 294*bf9bccc1SDan Williams struct nd_namespace_index *nsindex; 295*bf9bccc1SDan Williams unsigned long *free; 296*bf9bccc1SDan Williams u32 nslot, slot; 297*bf9bccc1SDan Williams int count = 0; 298*bf9bccc1SDan Williams 299*bf9bccc1SDan Williams if (!preamble_current(ndd, &nsindex, &free, &nslot)) 300*bf9bccc1SDan Williams return 0; 301*bf9bccc1SDan Williams 302*bf9bccc1SDan Williams for_each_clear_bit_le(slot, free, nslot) { 303*bf9bccc1SDan Williams struct nd_namespace_label *nd_label; 304*bf9bccc1SDan Williams 305*bf9bccc1SDan Williams nd_label = nd_label_base(ndd) + slot; 306*bf9bccc1SDan Williams 307*bf9bccc1SDan Williams if (!slot_valid(nd_label, slot)) { 308*bf9bccc1SDan Williams u32 label_slot = __le32_to_cpu(nd_label->slot); 309*bf9bccc1SDan Williams u64 size = __le64_to_cpu(nd_label->rawsize); 310*bf9bccc1SDan Williams u64 dpa = __le64_to_cpu(nd_label->dpa); 311*bf9bccc1SDan Williams 312*bf9bccc1SDan Williams dev_dbg(ndd->dev, 313*bf9bccc1SDan Williams "%s: slot%d invalid slot: %d dpa: %llx size: %llx\n", 314*bf9bccc1SDan Williams __func__, slot, label_slot, dpa, size); 315*bf9bccc1SDan Williams continue; 316*bf9bccc1SDan Williams } 317*bf9bccc1SDan Williams count++; 318*bf9bccc1SDan Williams } 319*bf9bccc1SDan Williams return count; 320*bf9bccc1SDan Williams } 321*bf9bccc1SDan Williams 322*bf9bccc1SDan Williams struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n) 323*bf9bccc1SDan Williams { 324*bf9bccc1SDan Williams struct nd_namespace_index *nsindex; 325*bf9bccc1SDan Williams unsigned long *free; 326*bf9bccc1SDan Williams u32 nslot, slot; 327*bf9bccc1SDan Williams 328*bf9bccc1SDan Williams if (!preamble_current(ndd, &nsindex, &free, &nslot)) 329*bf9bccc1SDan Williams return NULL; 330*bf9bccc1SDan Williams 331*bf9bccc1SDan Williams for_each_clear_bit_le(slot, free, nslot) { 332*bf9bccc1SDan Williams struct nd_namespace_label *nd_label; 333*bf9bccc1SDan Williams 334*bf9bccc1SDan Williams nd_label = nd_label_base(ndd) + slot; 335*bf9bccc1SDan Williams if (!slot_valid(nd_label, slot)) 336*bf9bccc1SDan Williams continue; 337*bf9bccc1SDan Williams 338*bf9bccc1SDan Williams if (n-- == 0) 339*bf9bccc1SDan Williams return nd_label_base(ndd) + slot; 340*bf9bccc1SDan Williams } 341*bf9bccc1SDan Williams 342*bf9bccc1SDan Williams return NULL; 343*bf9bccc1SDan Williams } 344