From: Nabeel M Mohamed <nmeeramohide@xxxxxxxxxx> This adds headers containing the following on-media formats: - Mpool superblock - Object management records: create, update, delete, and erase - Mpool configuration record - Media class config and spare record - OID checkpoint and version record - Mlog page header and framing records Co-developed-by: Greg Becker <gbecker@xxxxxxxxxx> Signed-off-by: Greg Becker <gbecker@xxxxxxxxxx> Co-developed-by: Pierre Labat <plabat@xxxxxxxxxx> Signed-off-by: Pierre Labat <plabat@xxxxxxxxxx> Co-developed-by: John Groves <jgroves@xxxxxxxxxx> Signed-off-by: John Groves <jgroves@xxxxxxxxxx> Signed-off-by: Nabeel M Mohamed <nmeeramohide@xxxxxxxxxx> --- drivers/mpool/omf.h | 593 ++++++++++++++++++++++++++++++++++++++++ drivers/mpool/omf_if.h | 381 ++++++++++++++++++++++++++ drivers/mpool/upgrade.h | 128 +++++++++ 3 files changed, 1102 insertions(+) create mode 100644 drivers/mpool/omf.h create mode 100644 drivers/mpool/omf_if.h create mode 100644 drivers/mpool/upgrade.h diff --git a/drivers/mpool/omf.h b/drivers/mpool/omf.h new file mode 100644 index 000000000000..c750573720dd --- /dev/null +++ b/drivers/mpool/omf.h @@ -0,0 +1,593 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2015-2020 Micron Technology, Inc. All rights reserved. + */ +/* + * Pool on-drive format (omf) module. + * + * Defines: + * + on-drive format for mpool superblocks + * + on-drive formats for mlogs, mblocks, and metadata containers (mdc) + * + utility functions for working with these on-drive formats + * That includes structures and enums used by the on-drive format. + * + * All mpool metadata is versioned and stored on media in little-endian format. + * + * Naming conventions: + * ------------------- + * The name of the structures ends with _omf + * The name of the structure members start with a "p" that means "packed". + */ + +#ifndef MPOOL_OMF_H +#define MPOOL_OMF_H + +#include <linux/bug.h> +#include <asm/byteorder.h> + +/* + * The following two macros exist solely to enable the OMF_SETGET macros to + * work on 8 bit members as well as 16, 32 and 64 bit members. + */ +#define le8_to_cpu(x) (x) +#define cpu_to_le8(x) (x) + + +/* Helper macro to define set/get methods for 8, 16, 32 or 64 bit scalar OMF struct members. */ +#define OMF_SETGET(type, member, bits) \ + OMF_SETGET2(type, member, bits, member) + +#define OMF_SETGET2(type, member, bits, name) \ + static __always_inline u##bits omf_##name(const type * s) \ + { \ + BUILD_BUG_ON(sizeof(((type *)0)->member)*8 != (bits)); \ + return le##bits##_to_cpu(s->member); \ + } \ + static __always_inline void omf_set_##name(type *s, u##bits val)\ + { \ + s->member = cpu_to_le##bits(val); \ + } + +/* Helper macro to define set/get methods for character strings embedded in OMF structures. */ +#define OMF_SETGET_CHBUF(type, member) \ + OMF_SETGET_CHBUF2(type, member, member) + +#define OMF_SETGET_CHBUF2(type, member, name) \ + static inline void omf_set_##name(type *s, const void *p, size_t plen) \ + { \ + size_t len = sizeof(((type *)0)->member); \ + memcpy(s->member, p, len < plen ? len : plen); \ + } \ + static inline void omf_##name(const type *s, void *p, size_t plen)\ + { \ + size_t len = sizeof(((type *)0)->member); \ + memcpy(p, s->member, len < plen ? len : plen); \ + } + + +/* MPOOL_NAMESZ_MAX should match OMF_MPOOL_NAME_LEN */ +#define OMF_MPOOL_NAME_LEN 32 + +/* MPOOL_UUID_SIZE should match OMF_UUID_PACKLEN */ +#define OMF_UUID_PACKLEN 16 + +/** + * enum mc_features_omf - Drive features that participate in media classes + * definition. These values are ored in a 64 bits field. + */ +enum mc_features_omf { + OMF_MC_FEAT_MLOG_TGT = 0x1, + OMF_MC_FEAT_MBLOCK_TGT = 0x2, + OMF_MC_FEAT_CHECKSUM = 0x4, +}; + + +/** + * enum devtype_omf - + * @OMF_PD_DEV_TYPE_BLOCK_STREAM: Block device implementing streams. + * @OMF_PD_DEV_TYPE_BLOCK_STD: Standard (non-streams) device (SSD, HDD). + * @OMF_PD_DEV_TYPE_FILE: File in user space for UT. + * @OMF_PD_DEV_TYPE_MEM: Memory semantic device. Such as NVDIMM + * direct access (raw or dax mode). + * @OMF_PD_DEV_TYPE_ZONE: zone-like device, such as open channel SSD + * (OC-SSD) and SMR HDD (using ZBC/ZAC). + * @OMF_PD_DEV_TYPE_BLOCK_NVDIMM: Standard (non-streams) NVDIMM in sector mode. + */ +enum devtype_omf { + OMF_PD_DEV_TYPE_BLOCK_STREAM = 1, + OMF_PD_DEV_TYPE_BLOCK_STD = 2, + OMF_PD_DEV_TYPE_FILE = 3, + OMF_PD_DEV_TYPE_MEM = 4, + OMF_PD_DEV_TYPE_ZONE = 5, + OMF_PD_DEV_TYPE_BLOCK_NVDIMM = 6, +}; + + +/** + * struct layout_descriptor_omf - Layout descriptor version 1. + * @pol_zcnt: number of zones + * @pol_zaddr: zone start addr + * + * Introduced with binary version 1.0.0.0. + * "pol_" = packed omf layout + */ +struct layout_descriptor_omf { + __le32 pol_zcnt; + __le64 pol_zaddr; +} __packed; + +/* Define set/get methods for layout_descriptor_omf */ +OMF_SETGET(struct layout_descriptor_omf, pol_zcnt, 32) +OMF_SETGET(struct layout_descriptor_omf, pol_zaddr, 64) +#define OMF_LAYOUT_DESC_PACKLEN (sizeof(struct layout_descriptor_omf)) + + +/** + * struct devparm descriptor_omf - packed omf devparm descriptor + * @podp_devid: UUID for drive + * @podp_zonetot: total number of zones + * @podp_devsz: size of partition in bytes + * @podp_features: Features, ored bits of enum mc_features_omf + * @podp_mclassp: enum mp_media_classp + * @podp_devtype: PD type (enum devtype_omf) + * @podp_sectorsz: 2^podp_sectorsz = sector size + * @podp_zonepg: zone size in number of zone pages + * + * The fields mclassp, devtype, sectosz, and zonepg uniquely identify the media class of the PD. + * All drives in a media class must have the same values in these fields. + */ +struct devparm_descriptor_omf { + u8 podp_mclassp; + u8 podp_devtype; + u8 podp_sectorsz; + u8 podp_devid[OMF_UUID_PACKLEN]; + u8 podp_pad[5]; + __le32 podp_zonepg; + __le32 podp_zonetot; + __le64 podp_devsz; + __le64 podp_features; +} __packed; + +/* Define set/get methods for devparm_descriptor_omf */ +OMF_SETGET(struct devparm_descriptor_omf, podp_mclassp, 8) +OMF_SETGET(struct devparm_descriptor_omf, podp_devtype, 8) +OMF_SETGET(struct devparm_descriptor_omf, podp_sectorsz, 8) +OMF_SETGET_CHBUF(struct devparm_descriptor_omf, podp_devid) +OMF_SETGET(struct devparm_descriptor_omf, podp_zonepg, 32) +OMF_SETGET(struct devparm_descriptor_omf, podp_zonetot, 32) +OMF_SETGET(struct devparm_descriptor_omf, podp_devsz, 64) +OMF_SETGET(struct devparm_descriptor_omf, podp_features, 64) +#define OMF_DEVPARM_DESC_PACKLEN (sizeof(struct devparm_descriptor_omf)) + + +/* + * mlog structure: + * + An mlog comprises a consecutive sequence of log blocks, + * where each log block is a single page within a zone + * + A log block comprises a header and a consecutive sequence of records + * + A record is a typed blob + * + * Log block headers must be versioned. Log block records do not + * require version numbers because they are typed and new types can + * always be added. + */ + +/* + * Log block format -- version 1 + * + * log block := header record+ eolb? trailer? + * + * header := struct omf_logblock_header where vers=2 + * + * record := lrd byte* + * + * lrd := struct omf_logrec_descriptor with value + * (<record length>, <chunk length>, enum logrec_type_omf value) + * + * eolb (end of log block marker) := struct omf_logrec_descriptor with value + * (0, 0, enum logrec_type_omf.EOLB/0) + * + * trailer := zero bytes from end of last log block record to end of log block + * + * OMF_LOGREC_CEND must be the max. value for this enum. + */ + +/** + * enum logrec_type_omf - + * @OMF_LOGREC_EOLB: end of log block marker (start of trailer) + * @OMF_LOGREC_DATAFULL: data record; contains all specified data + * @OMF_LOGREC_DATAFIRST: data record; contains first part of specified data + * @OMF_LOGREC_DATAMID: data record; contains interior part of data + * @OMF_LOGREC_DATALAST: data record; contains final part of specified data + * @OMF_LOGREC_CSTART: compaction start marker + * @OMF_LOGREC_CEND: compaction end marker + * + * A log record type of 0 signifies EOLB. This is really the start of the + * trailer but this simplifies parsing for partially filled log blocks. + * DATAFIRST, -MID, -LAST types are used for chunking logical data records. + */ +enum logrec_type_omf { + OMF_LOGREC_EOLB = 0, + OMF_LOGREC_DATAFULL = 1, + OMF_LOGREC_DATAFIRST = 2, + OMF_LOGREC_DATAMID = 3, + OMF_LOGREC_DATALAST = 4, + OMF_LOGREC_CSTART = 5, + OMF_LOGREC_CEND = 6, +}; + + +/** + * struct logrec_descriptor_omf -packed omf logrec descriptor + * @polr_tlen: logical length of data record (all chunks) + * @polr_rlen: length of data chunk in this log record + * @polr_rtype: enum logrec_type_omf value + */ +struct logrec_descriptor_omf { + __le32 polr_tlen; + __le16 polr_rlen; + u8 polr_rtype; + u8 polr_pad; +} __packed; + +/* Define set/get methods for logrec_descriptor_omf */ +OMF_SETGET(struct logrec_descriptor_omf, polr_tlen, 32) +OMF_SETGET(struct logrec_descriptor_omf, polr_rlen, 16) +OMF_SETGET(struct logrec_descriptor_omf, polr_rtype, 8) +#define OMF_LOGREC_DESC_PACKLEN (sizeof(struct logrec_descriptor_omf)) +#define OMF_LOGREC_DESC_RLENMAX 65535 + + +#define OMF_LOGBLOCK_VERS 1 + +/** + * struct logblock_header_omf - packed omf logblock header for all versions + * @polh_vers: log block hdr version, offset 0 in all vers + * @polh_magic: unique magic per mlog + * @polh_pfsetid: flush set ID of the previous log block + * @polh_cfsetid: flush set ID this log block belongs to + * @polh_gen: generation number + */ +struct logblock_header_omf { + __le16 polh_vers; + u8 polh_magic[OMF_UUID_PACKLEN]; + u8 polh_pad[6]; + __le32 polh_pfsetid; + __le32 polh_cfsetid; + __le64 polh_gen; +} __packed; + +/* Define set/get methods for logblock_header_omf */ +OMF_SETGET(struct logblock_header_omf, polh_vers, 16) +OMF_SETGET_CHBUF(struct logblock_header_omf, polh_magic) +OMF_SETGET(struct logblock_header_omf, polh_pfsetid, 32) +OMF_SETGET(struct logblock_header_omf, polh_cfsetid, 32) +OMF_SETGET(struct logblock_header_omf, polh_gen, 64) +/* On-media log block header length */ +#define OMF_LOGBLOCK_HDR_PACKLEN (sizeof(struct logblock_header_omf)) + + +/* + * Metadata container (mdc) mlog data record formats. + * + * NOTE: mdc records are typed and as such do not need a version number as new + * types can always be added as required. + */ +/** + * enum mdcrec_type_omf - + * @OMF_MDR_UNDEF: undefined; should never occur + * @OMF_MDR_OCREATE: object create + * @OMF_MDR_OUPDATE: object update + * @OMF_MDR_ODELETE: object delete + * @OMF_MDR_OIDCKPT: object id checkpoint + * @OMF_MDR_OERASE: object erase, also log mlog gen number + * @OMF_MDR_MCCONFIG: media class config + * @OMF_MDR_MCSPARE: media class spare zones set + * @OMF_MDR_VERSION: MDC content version. + * @OMF_MDR_MPCONFIG: mpool config record + */ +enum mdcrec_type_omf { + OMF_MDR_UNDEF = 0, + OMF_MDR_OCREATE = 1, + OMF_MDR_OUPDATE = 2, + OMF_MDR_ODELETE = 3, + OMF_MDR_OIDCKPT = 4, + OMF_MDR_OERASE = 5, + OMF_MDR_MCCONFIG = 6, + OMF_MDR_MCSPARE = 7, + OMF_MDR_VERSION = 8, + OMF_MDR_MPCONFIG = 9, + OMF_MDR_MAX = 10, +}; + +/** + * struct mdcver_omf - packed mdc version, version of an mpool MDC content. + * @pv_rtype: OMF_MDR_VERSION + * @pv_mdcv_major: to compare with MAJOR in binary version. + * @pv_mdcv_minor: to compare with MINOR in binary version. + * @pv_mdcv_patch: to compare with PATCH in binary version. + * @pv_mdcv_dev: used during development cycle when the above + * numbers don't change. + * + * This is not the version of the message framing used for the MDC. This is + * version of the binary that introduced that version of the MDC content. + */ +struct mdcver_omf { + u8 pv_rtype; + u8 pv_pad; + __le16 pv_mdcv_major; + __le16 pv_mdcv_minor; + __le16 pv_mdcv_patch; + __le16 pv_mdcv_dev; +} __packed; + +/* Define set/get methods for mdcrec_version_omf */ +OMF_SETGET(struct mdcver_omf, pv_rtype, 8) +OMF_SETGET(struct mdcver_omf, pv_mdcv_major, 16) +OMF_SETGET(struct mdcver_omf, pv_mdcv_minor, 16) +OMF_SETGET(struct mdcver_omf, pv_mdcv_patch, 16) +OMF_SETGET(struct mdcver_omf, pv_mdcv_dev, 16) + + +/** + * struct mdcrec_data_odelete_omf - packed data record odelete + * @pdro_rtype: mdrec_type_omf:OMF_MDR_ODELETE, OMF_MDR_OIDCKPT + * @pdro_objid: object identifier + */ +struct mdcrec_data_odelete_omf { + u8 pdro_rtype; + u8 pdro_pad[7]; + __le64 pdro_objid; +} __packed; + +/* Define set/get methods for mdcrec_data_odelete_omf */ +OMF_SETGET(struct mdcrec_data_odelete_omf, pdro_rtype, 8) +OMF_SETGET(struct mdcrec_data_odelete_omf, pdro_objid, 64) + + +/** + * struct mdcrec_data_oerase_omf - packed data record oerase + * @pdrt_rtype: mdrec_type_omf: OMF_MDR_OERASE + * @pdrt_objid: object identifier + * @pdrt_gen: object generation number + */ +struct mdcrec_data_oerase_omf { + u8 pdrt_rtype; + u8 pdrt_pad[7]; + __le64 pdrt_objid; + __le64 pdrt_gen; +} __packed; + +/* Define set/get methods for mdcrec_data_oerase_omf */ +OMF_SETGET(struct mdcrec_data_oerase_omf, pdrt_rtype, 8) +OMF_SETGET(struct mdcrec_data_oerase_omf, pdrt_objid, 64) +OMF_SETGET(struct mdcrec_data_oerase_omf, pdrt_gen, 64) +#define OMF_MDCREC_OERASE_PACKLEN (sizeof(struct mdcrec_data_oerase_omf)) + + +/** + * struct mdcrec_data_mcconfig_omf - packed data record mclass config + * @pdrs_rtype: mdrec_type_omf: OMF_MDR_MCCONFIG + * @pdrs_parm: + */ +struct mdcrec_data_mcconfig_omf { + u8 pdrs_rtype; + u8 pdrs_pad[7]; + struct devparm_descriptor_omf pdrs_parm; +} __packed; + + +OMF_SETGET(struct mdcrec_data_mcconfig_omf, pdrs_rtype, 8) +#define OMF_MDCREC_MCCONFIG_PACKLEN (sizeof(struct mdcrec_data_mcconfig_omf)) + + +/** + * struct mdcrec_data_mcspare_omf - packed data record mcspare + * @pdra_rtype: mdrec_type_omf: OMF_MDR_MCSPARE + * @pdra_mclassp: enum mp_media_classp + * @pdra_spzone: percent spare zones for drives in media class + */ +struct mdcrec_data_mcspare_omf { + u8 pdra_rtype; + u8 pdra_mclassp; + u8 pdra_spzone; +} __packed; + +/* Define set/get methods for mdcrec_data_mcspare_omf */ +OMF_SETGET(struct mdcrec_data_mcspare_omf, pdra_rtype, 8) +OMF_SETGET(struct mdcrec_data_mcspare_omf, pdra_mclassp, 8) +OMF_SETGET(struct mdcrec_data_mcspare_omf, pdra_spzone, 8) +#define OMF_MDCREC_CLS_SPARE_PACKLEN (sizeof(struct mdcrec_data_mcspare_omf)) + + +/** + * struct mdcrec_data_ocreate_omf - packed data record ocreate + * @pdrc_rtype: mdrec_type_omf: OMF_MDR_OCREATE or OMF_MDR_OUPDATE + * @pdrc_mclass: + * @pdrc_uuid: + * @pdrc_ld: + * @pdrc_objid: object identifier + * @pdrc_gen: object generation number + * @pdrc_mblen: amount of data written in the mblock, for mlog this is 0 + * @pdrc_uuid: Used only for mlogs. Must be at the end of this struct. + */ +struct mdcrec_data_ocreate_omf { + u8 pdrc_rtype; + u8 pdrc_mclass; + u8 pdrc_pad[2]; + struct layout_descriptor_omf pdrc_ld; + __le64 pdrc_objid; + __le64 pdrc_gen; + __le64 pdrc_mblen; + u8 pdrc_uuid[]; +} __packed; + +/* Define set/get methods for mdcrec_data_ocreate_omf */ +OMF_SETGET(struct mdcrec_data_ocreate_omf, pdrc_rtype, 8) +OMF_SETGET(struct mdcrec_data_ocreate_omf, pdrc_mclass, 8) +OMF_SETGET(struct mdcrec_data_ocreate_omf, pdrc_objid, 64) +OMF_SETGET(struct mdcrec_data_ocreate_omf, pdrc_gen, 64) +OMF_SETGET(struct mdcrec_data_ocreate_omf, pdrc_mblen, 64) +#define OMF_MDCREC_OBJCMN_PACKLEN (sizeof(struct mdcrec_data_ocreate_omf) + \ + OMF_UUID_PACKLEN) + + +/** + * struct mdcrec_data_mpconfig_omf - packed data mpool config + * @pdmc_rtype: + * @pdmc_oid1: + * @pdmc_oid2: + * @pdmc_uid: + * @pdmc_gid: + * @pdmc_mode: + * @pdmc_mclassp: + * @pdmc_captgt: + * @pdmc_ra_pages_max: + * @pdmc_vma_size_max: + * @pdmc_utype: user-defined type (uuid) + * @pdmc_label: user-defined label (ascii) + */ +struct mdcrec_data_mpconfig_omf { + u8 pdmc_rtype; + u8 pdmc_pad[7]; + __le64 pdmc_oid1; + __le64 pdmc_oid2; + __le32 pdmc_uid; + __le32 pdmc_gid; + __le32 pdmc_mode; + __le32 pdmc_rsvd0; + __le64 pdmc_captgt; + __le32 pdmc_ra_pages_max; + __le32 pdmc_vma_size_max; + __le32 pdmc_rsvd1; + __le32 pdmc_rsvd2; + __le64 pdmc_rsvd3; + __le64 pdmc_rsvd4; + u8 pdmc_utype[16]; + u8 pdmc_label[MPOOL_LABELSZ_MAX]; +} __packed; + +/* Define set/get methods for mdcrec_data_mpconfig_omf */ +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_rtype, 8) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_oid1, 64) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_oid2, 64) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_uid, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_gid, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_mode, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_rsvd0, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_captgt, 64) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_ra_pages_max, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_vma_size_max, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_rsvd1, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_rsvd2, 32) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_rsvd3, 64) +OMF_SETGET(struct mdcrec_data_mpconfig_omf, pdmc_rsvd4, 64) +OMF_SETGET_CHBUF(struct mdcrec_data_mpconfig_omf, pdmc_utype) +OMF_SETGET_CHBUF(struct mdcrec_data_mpconfig_omf, pdmc_label) +#define OMF_MDCREC_MPCONFIG_PACKLEN (sizeof(struct mdcrec_data_mpconfig_omf)) + + +/* + * Object types embedded in opaque uint64 object ids by the pmd module. + * This encoding is also present in the object ids stored in the + * data records on media. + * + * The obj_type field is 4 bits. There are two valid obj types. + */ +enum obj_type_omf { + OMF_OBJ_UNDEF = 0, + OMF_OBJ_MBLOCK = 1, + OMF_OBJ_MLOG = 2, +}; + +/** + * sb_descriptor_ver_omf - Mpool super block version + * @OMF_SB_DESC_UNDEF: value not on media + */ +enum sb_descriptor_ver_omf { + OMF_SB_DESC_UNDEF = 0, + OMF_SB_DESC_V1 = 1, + +}; +#define OMF_SB_DESC_VER_LAST OMF_SB_DESC_V1 + + +/** + * struct sb_descriptor_omf - packed super block, super block descriptor format version 1. + * @psb_magic: mpool magic value; offset 0 in all vers + * @psb_name: mpool name + * @psb_poolid: UUID of pool this drive belongs to + * @psb_vers: sb format version; offset 56 + * @psb_gen: sb generation number on this drive + * @psb_cksum1: checksum of all fields above + * @psb_parm: parameters for this drive + * @psb_cksum2: checksum of psb_parm + * @psb_mdc01gen: mdc0 log1 generation number + * @psb_mdc01uuid: + * @psb_mdc01devid: mdc0 log1 device UUID + * @psb_mdc01strip: mdc0 log1 strip desc. + * @psb_mdc01desc: mdc0 log1 layout + * @psb_mdc02gen: mdc0 log2 generation number + * @psb_mdc02uuid: + * @psb_mdc02devid: mdc0 log2 device UUID + * @psb_mdc02strip: mdc0 log2 strip desc. + * @psb_mdc02desc: mdc0 log2 layout + * @psb_mdc0dev: drive param for mdc0 strip + * + * Note: these fields, up to and including psb_cksum1, are known to libblkid. + * cannot change them without havoc. Fields from psb_magic to psb_cksum1 + * included are at same offset in all versions. + */ +struct sb_descriptor_omf { + __le64 psb_magic; + u8 psb_name[OMF_MPOOL_NAME_LEN]; + u8 psb_poolid[OMF_UUID_PACKLEN]; + __le16 psb_vers; + __le32 psb_gen; + u8 psb_cksum1[4]; + + u8 psb_pad1[6]; + struct devparm_descriptor_omf psb_parm; + u8 psb_cksum2[4]; + + u8 psb_pad2[4]; + __le64 psb_mdc01gen; + u8 psb_mdc01uuid[OMF_UUID_PACKLEN]; + u8 psb_mdc01devid[OMF_UUID_PACKLEN]; + struct layout_descriptor_omf psb_mdc01desc; + + u8 psb_pad3[4]; + __le64 psb_mdc02gen; + u8 psb_mdc02uuid[OMF_UUID_PACKLEN]; + u8 psb_mdc02devid[OMF_UUID_PACKLEN]; + struct layout_descriptor_omf psb_mdc02desc; + + u8 psb_pad4[4]; + struct devparm_descriptor_omf psb_mdc0dev; +} __packed; + +OMF_SETGET(struct sb_descriptor_omf, psb_magic, 64) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_name) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_poolid) +OMF_SETGET(struct sb_descriptor_omf, psb_vers, 16) +OMF_SETGET(struct sb_descriptor_omf, psb_gen, 32) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_cksum1) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_cksum2) +OMF_SETGET(struct sb_descriptor_omf, psb_mdc01gen, 64) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_mdc01uuid) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_mdc01devid) +OMF_SETGET(struct sb_descriptor_omf, psb_mdc02gen, 64) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_mdc02uuid) +OMF_SETGET_CHBUF(struct sb_descriptor_omf, psb_mdc02devid) +#define OMF_SB_DESC_PACKLEN (sizeof(struct sb_descriptor_omf)) + +/* + * For object-related records OCREATE/OUPDATE is max so compute that here as: + * rtype + objid + gen + layout desc + */ +#define OMF_MDCREC_PACKLEN_MAX max(OMF_MDCREC_OBJCMN_PACKLEN, \ + max(OMF_MDCREC_MCCONFIG_PACKLEN, \ + max(OMF_MDCREC_CLS_SPARE_PACKLEN, \ + OMF_MDCREC_MPCONFIG_PACKLEN))) + +#endif /* MPOOL_OMF_H */ diff --git a/drivers/mpool/omf_if.h b/drivers/mpool/omf_if.h new file mode 100644 index 000000000000..5f11a03ef500 --- /dev/null +++ b/drivers/mpool/omf_if.h @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2015-2020 Micron Technology, Inc. All rights reserved. + */ + +#ifndef MPOOL_OMF_IF_H +#define MPOOL_OMF_IF_H + +#include "uuid.h" +#include "mpool_ioctl.h" + +#include "mp.h" +#include "omf.h" + +struct mpool_descriptor; +struct pmd_layout; + +/* + * Common defs: versioned via version number field of enclosing structs + */ + +/** + * struct omf_layout_descriptor - version 1 layout descriptor + * @ol_zaddr: + * @ol_zcnt: number of zones + * @ol_pdh: + */ +struct omf_layout_descriptor { + u64 ol_zaddr; + u32 ol_zcnt; + u16 ol_pdh; +}; + +/** + * struct omf_devparm_descriptor - version 1 devparm descriptor + * @odp_devid: UUID for drive + * @odp_devsz: size, in bytes, of the volume/device + * @odp_zonetot: total number of zones + * @odp_zonepg: zone size in number of zone pages + * @odp_mclassp: enum mp_media_classp + * @odp_devtype: PD type. Enum pd_devtype + * @odp_sectorsz: 2^podp_sectorsz = sector size + * @odp_features: Features, ored bits of enum mp_mc_features + * + * The fields zonepg, mclassp, devtype, sectosz, and features uniquely identify + * the media class of the PD. + * All drives in a media class must have the same values in the below fields. + */ +struct omf_devparm_descriptor { + struct mpool_uuid odp_devid; + u64 odp_devsz; + u32 odp_zonetot; + + u32 odp_zonepg; + u8 odp_mclassp; + u8 odp_devtype; + u8 odp_sectorsz; + u64 odp_features; +}; + +/* + * Superblock (sb) -- version 1 + * + * Note this is 8-byte-wide reversed to get correct ascii order + */ +#define OMF_SB_MAGIC 0x7665446c6f6f706dULL /* ASCII mpoolDev - no null */ + +/** + * struct omf_sb_descriptor - version 1 superblock descriptor + * @osb_magic: mpool magic value + * @osb_name: mpool name, contains a terminating 0 byte + * @osb_cktype: enum mp_cksum_type value + * @osb_vers: sb format version + * @osb_poolid: UUID of pool this drive belongs to + * @osb_gen: sb generation number on this drive + * @osb_parm: parameters for this drive + * @osb_mdc01gen: mdc0 log1 generation number + * @osb_mdc01uuid: + * @osb_mdc01devid: + * @osb_mdc01desc: mdc0 log1 layout + * @osb_mdc02gen: mdc0 log2 generation number + * @osb_mdc02uuid: + * @osb_mdc02devid: + * @osb_mdc02desc: mdc0 log2 layout + * @osb_mdc0dev: drive param for mdc0 + */ +struct omf_sb_descriptor { + u64 osb_magic; + u8 osb_name[MPOOL_NAMESZ_MAX]; + u8 osb_cktype; + u16 osb_vers; + struct mpool_uuid osb_poolid; + u32 osb_gen; + struct omf_devparm_descriptor osb_parm; + + u64 osb_mdc01gen; + struct mpool_uuid osb_mdc01uuid; + struct mpool_uuid osb_mdc01devid; + struct omf_layout_descriptor osb_mdc01desc; + + u64 osb_mdc02gen; + struct mpool_uuid osb_mdc02uuid; + struct mpool_uuid osb_mdc02devid; + struct omf_layout_descriptor osb_mdc02desc; + + struct omf_devparm_descriptor osb_mdc0dev; +}; + +/** + * struct omf_logrec_descriptor - + * @olr_tlen: logical length of data record (all chunks) + * @olr_rlen: length of data chunk in this log record + * @olr_rtype: enum logrec_type_omf value + * + */ +struct omf_logrec_descriptor { + u32 olr_tlen; + u16 olr_rlen; + u8 olr_rtype; +}; + +/** + * struct omf_logblock_header - + * @olh_magic: unique ID per mlog + * @olh_pfsetid: flush set ID of the previous log block + * @olh_cfsetid: flush set ID this log block + * @olh_gen: generation number + * @olh_vers: log block format version + */ +struct omf_logblock_header { + struct mpool_uuid olh_magic; + u32 olh_pfsetid; + u32 olh_cfsetid; + u64 olh_gen; + u16 olh_vers; +}; + +/** + * struct omf_mdcver - version of an mpool MDC content. + * @mdcver: + * + * mdcver[0]: major version number + * mdcver[1]: minor version number + * mdcver[2]: patch version number + * mdcver[3]: development version number. Used during development cycle when + * the above numbers don't change. + * + * This is not the version of the message framing used for the MDC. + * This the version of the binary that introduced that version of the MDC + * content. + */ +struct omf_mdcver { + u16 mdcver[4]; +}; + +#define mdcv_major mdcver[0] +#define mdcv_minor mdcver[1] +#define mdcv_patch mdcver[2] +#define mdcv_dev mdcver[3] + +/** + * struct omf_mdcrec_data - + * @omd_version: OMF_MDR_VERSION record + * @omd_objid: object identifier + * @omd_gen: object generation number + * @omd_layout: + * @omd_mblen: Length of written data in object + * @omd_old: + * @omd_uuid: + * @omd_parm: + * @omd_mclassp: mp_media_classp + * @omd_spzone: percent spare zones for drives in media class + * @omd_cfg: + * @omd_rtype: enum mdcrec_type_omf value + * + * object-related rtypes: + * ODELETE, OIDCKPT: objid field only; others ignored + * OERASE: objid and gen fields only; others ignored + * OCREATE, OUPDATE: layout field only; others ignored + */ +struct omf_mdcrec_data { + union ustruct { + struct omf_mdcver omd_version; + + struct object { + u64 omd_objid; + u64 omd_gen; + struct pmd_layout *omd_layout; + u64 omd_mblen; + struct omf_layout_descriptor omd_old; + struct mpool_uuid omd_uuid; + u8 omd_mclass; + } obj; + + struct drive_state { + struct omf_devparm_descriptor omd_parm; + } dev; + + struct media_cls_spare { + u8 omd_mclassp; + u8 omd_spzone; + } mcs; + + struct mpool_config omd_cfg; + } u; + + u8 omd_rtype; +}; + +/** + * objid_type() - Return the type field from an objid + * @objid: + */ +static inline int objid_type(u64 objid) +{ + return ((objid & 0xF00) >> 8); +} + +static inline bool objtype_valid(enum obj_type_omf otype) +{ + return otype && (otype <= 2); +}; + +/* + * omf API functions -- exported functions for working with omf structures + */ + +/** + * omf_sb_pack_htole() - pack superblock + * @sb: struct omf_sb_descriptor * + * @outbuf: char * + * + * Pack superblock into outbuf little-endian computing specified checksum. + * + * Return: 0 if successful, -EINVAL otherwise + */ +int omf_sb_pack_htole(struct omf_sb_descriptor *sb, char *outbuf); + +/** + * omf_sb_unpack_letoh() - unpack superblock + * @sb: struct omf_sb_descriptor * + * @inbuf: char * + * @omf_ver: on-media-format superblock version + * + * Unpack little-endian superblock from inbuf into sb verifying checksum. + * + * Return: 0 if successful, -errno otherwise + */ +int omf_sb_unpack_letoh(struct omf_sb_descriptor *sb, const char *inbuf, u16 *omf_ver); + +/** + * omf_sb_has_magic_le() - Determine if buffer has superblock magic value + * @inbuf: char * + * + * Determine if little-endian buffer inbuf has superblock magic value + * where expected; does NOT imply inbuf is a valid superblock. + * + * Return: 1 if true; 0 otherwise + */ +bool omf_sb_has_magic_le(const char *inbuf); + +/** + * omf_logblock_header_pack_htole() - pack log block header + * @lbh: struct omf_logblock_header * + * @outbuf: char * + * + * Pack header into little-endian log block buffer lbuf, ex-checksum. + * + * Return: 0 if successful, -errno otherwise + */ +int omf_logblock_header_pack_htole(struct omf_logblock_header *lbh, char *lbuf); + +/** + * omf_logblock_header_len_le() - Determine header length of log block + * @lbuf: char * + * + * Check little-endian log block in lbuf to determine header length. + * + * Return: bytes in packed header; -EINVAL if invalid header vers + */ +int omf_logblock_header_len_le(char *lbuf); + +/** + * omf_logblock_header_unpack_letoh() - unpack log block header + * @lbh: struct omf_logblock_header * + * @inbuf: char * + * + * Unpack little-endian log block header from lbuf into lbh; does not + * verify checksum. + * + * Return: 0 if successful, -EINVAL if invalid log block header vers + */ +int omf_logblock_header_unpack_letoh(struct omf_logblock_header *lbh, const char *inbuf); + +/** + * omf_logrec_desc_pack_htole() - pack log record descriptor + * @lrd: struct omf_logrec_descriptor * + * @outbuf: char * + * + * Pack log record descriptor into outbuf little-endian. + * + * Return: 0 if successful, -EINVAL if invalid log rec type + */ +int omf_logrec_desc_pack_htole(struct omf_logrec_descriptor *lrd, char *outbuf); + +/** + * omf_logrec_desc_unpack_letoh() - unpack log record descriptor + * @lrd: struct omf_logrec_descriptor * + * @inbuf: char * + * + * Unpack little-endian log record descriptor from inbuf into lrd. + */ +void omf_logrec_desc_unpack_letoh(struct omf_logrec_descriptor *lrd, const char *inbuf); + +/** + * omf_mdcrec_pack_htole() - pack mdc record + * @mp: struct mpool_descriptor * + * @cdr: struct omf_mdcrec_data * + * @outbuf: char * + * + * Pack mdc record into outbuf little-endian. + * NOTE: Assumes outbuf has enough space for the layout structure. + * + * Return: bytes packed if successful, -EINVAL otherwise + */ +int omf_mdcrec_pack_htole(struct mpool_descriptor *mp, struct omf_mdcrec_data *cdr, char *outbuf); + +/** + * omf_mdcrec_unpack_letoh() - unpack mdc record + * @mdcver: mdc content version of the mdc from which this data comes. + * NULL means latest MDC content version known by this binary. + * @mp: struct mpool_descriptor * + * @cdr: struct omf_mdcrec_data * + * @inbuf: char * + * + * Unpack little-endian mdc record from inbuf into cdr. + * + * Return: 0 if successful, -errno on error + */ +int omf_mdcrec_unpack_letoh(struct omf_mdcver *mdcver, struct mpool_descriptor *mp, + struct omf_mdcrec_data *cdr, const char *inbuf); + +/** + * omf_mdcrec_isobj_le() - determine if mdc recordis object-related + * @inbuf: char * + * + * Return true if little-endian mdc record in inbuf is object-related. + */ +int omf_mdcrec_isobj_le(const char *inbuf); + +/** + * omf_mdcver_unpack_letoh() - Unpack le mdc version record from inbuf. + * @cdr: + * @inbuf: + */ +void omf_mdcver_unpack_letoh(struct omf_mdcrec_data *cdr, const char *inbuf); + +/** + * omf_mdcrec_unpack_type_letoh() - extract the record type from a packed MDC record. + * @inbuf: packed MDC record. + */ +u8 omf_mdcrec_unpack_type_letoh(const char *inbuf); + +/** + * logrec_type_datarec() - data record or not + * @rtype: + * + * Return: true if the log record type is related to a data record. + */ +bool logrec_type_datarec(enum logrec_type_omf rtype); + +/** + * omf_sbver_to_mdcver() - Returns the matching mdc version for a given superblock version + * @sbver: superblock version + */ +struct omf_mdcver *omf_sbver_to_mdcver(enum sb_descriptor_ver_omf sbver); + +int omf_init(void) __cold; +void omf_exit(void) __cold; + +#endif /* MPOOL_OMF_IF_H */ diff --git a/drivers/mpool/upgrade.h b/drivers/mpool/upgrade.h new file mode 100644 index 000000000000..3b3748c47a3e --- /dev/null +++ b/drivers/mpool/upgrade.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2015-2020 Micron Technology, Inc. All rights reserved. + */ + +/* + * Defines structures for upgrading MPOOL meta data + */ + +#ifndef MPOOL_UPGRADE_H +#define MPOOL_UPGRADE_H + +#include "omf_if.h" + +/* + * Size of version converted to string. + * 4 * (5 bytes for a u16) + 3 * (1 byte for the '.') + 1 byte for \0 + */ +#define MAX_MDCVERSTR 24 + +/* + * Naming conventions: + * + * omf structures: + * --------------- + * The old structure names end with _omf_v<version number>. + * For example: layout_descriptor_omf_v1 + * The current/latest structure name end simply with _omf. + * For example: layout_descriptor_omf + * + * Conversion functions: + * --------------------- + * They are named like: + * omf_convert_<blabla>_<maj>_<min>_<patch>_<dev>to<maj>_<min>_<patch>_<dev>() + * + * For example: omf_convert_sb_1_0_0_0to1_0_0_1() + * + * They are not named like omf_convert_<blabla>_v1tov2() because sometimes the + * input and output structures are exactly the same and the conversion is + * related to some subtle interpretation of structure filed[s] content. + * + * Unpack functions: + * ----------------- + * They are named like: + * omf_<blabla>_unpack_letoh_v<version number>() + * <version number> being the version of the structure. + * + * For example: omf_layout_unpack_letoh_v1() + * Note that for the latest/current version of the structure we cannot + * name the unpack function omf_<blabla>_unpack_letoh() because that would + * introduce a name conflict with the top unpack function that calls + * omf_unpack_letoh_and_convert() + * + * For example for layout we have: + * omf_layout_unpack_letoh_v1() unpacks layout_descriptor_omf_v1 + * omf_layout_unpack_letoh_v2() unpacks layout_descriptor_omf + * omf_layout_unpack_letoh() calls one of the two above. + */ + +/** + * struct upgrade_history - + * @uh_size: size of the current version in-memory structure + * @uh_unpack: unpacking function from on-media format to in-memory format + * @uh_conv: conversion function from previous version to current version, + * set to NULL for the first version + * @uh_sbver: corresponding superblock version since which the change has + * been introduced. If this structure is not used by superblock + * set uh_sbver = OMF_SB_DESC_UNDEF. + * @uh_mdcver: corresponding mdc ver since which the change has been + * introduced + * + * Every time we update a nested structure in superblock or MDC, we need to + * save the following information about this update, such that we can keep the + * update history of this structure + */ +struct upgrade_history { + size_t uh_size; + int (*uh_unpack)(void *out, const char *inbuf); + int (*uh_conv)(const void *pre, void *cur); + enum sb_descriptor_ver_omf uh_sbver; + struct omf_mdcver uh_mdcver; +}; + +/** + * omfu_mdcver_cur() - Return the latest mpool MDC content version understood by this binary + */ +struct omf_mdcver *omfu_mdcver_cur(void); + +/** + * omfu_mdcver_comment() - Return mpool MDC content version comment passed in via "mdcver". + * @mdcver: + */ +const char *omfu_mdcver_comment(struct omf_mdcver *mdcver); + +/** + * omfu_mdcver_to_str() - convert a version into a string. + * @mdcver: version to convert + * @buf: buffer in which to place the conversion. + * @sz: size of "buf" in bytes. + * + * Returns "buf" + */ +char *omfu_mdcver_to_str(struct omf_mdcver *mdcver, char *buf, size_t sz); + +/** + * omfu_mdcver_cmp() - compare two versions a and b + * @a: first version + * @op: compare operator (C syntax), can be "<", "<=", ">", ">=", "==". + * @b: second version + * + * Return (a op b) + */ +bool omfu_mdcver_cmp(struct omf_mdcver *a, char *op, struct omf_mdcver *b); + +/** + * omfu_mdcver_cmp2() - compare two versions + * @a: first version + * @op: compare operator (C syntax), can be "<", "<=", ">", ">=", "==". + * @major: major, minor, patch and dev which composes the second version + * @minor: + * @patch: + * @dev: + * + * Return true (a op b) + */ +bool omfu_mdcver_cmp2(struct omf_mdcver *a, char *op, u16 major, u16 minor, u16 patch, u16 dev); + +#endif /* MPOOL_UPGRADE_H */ -- 2.17.2