1 /* 2 * Copyright (c) 2014-2020 Douglas Gilbert. 3 * All rights reserved. 4 * Use of this source code is governed by a BSD-style 5 * license that can be found in the BSD_LICENSE file. 6 * 7 * SPDX-License-Identifier: BSD-2-Clause 8 */ 9 10 // C standard headers 11 #include <stdio.h> 12 #include <stdint.h> 13 #define __STDC_FORMAT_MACROS 1 14 #include <inttypes.h> 15 16 // C++ standard headers 17 #include <vector> 18 19 // This file is a C++ header file 20 21 22 #define SG_SGL_MAX_ELEMENTS 16384 23 24 #define SG_COUNT_INDEFINITE (-1) 25 #define SG_LBA_INVALID SG_COUNT_INDEFINITE 26 27 // Sizing matches largest SCSI READ and WRITE commands plus those of Unix 28 // read(2)s and write(2)s. User can give larger than 31 bit 'num's but they 29 // are split into several consecutive elements. 30 class scat_gath_elem { 31 public: 32 uint64_t lba; // of start block 33 uint32_t num; // number of blocks from and including start block 34 make_bad()35 void make_bad() { lba = UINT64_MAX; num = UINT32_MAX; } is_bad()36 bool is_bad() const { return (lba == UINT64_MAX && num == UINT32_MAX); } 37 }; 38 39 // Consider "linearity" as a scatter gather list property. Elements of this 40 // of from the strongest form to the weakest. 41 enum sgl_linearity_e { 42 SGL_LINEAR = 0, // empty list and 0,0 considered linear 43 SGL_MONOTONIC, // since not linear, implies holes 44 SGL_MONO_OVERLAP, // monotonic but same LBA in two or more elements 45 SGL_NON_MONOTONIC // weakest 46 }; 47 48 49 // Holds one scatter gather list and its associated metadata 50 class scat_gath_list { 51 public: scat_gath_list()52 scat_gath_list() : linearity(SGL_LINEAR), sum_hard(false), m_errno(0), 53 high_lba_p1(0), lowest_lba(0), sum(0) { } 54 55 scat_gath_list(const scat_gath_list &) = default; 56 scat_gath_list & operator=(const scat_gath_list &) = default; 57 ~scat_gath_list() = default; 58 59 bool empty() const; 60 bool empty_or_00() const; 61 int num_elems() const; 62 int64_t get_lowest_lba(bool ignore_degen, bool always_last) const; 63 int64_t get_low_lba_from_linear() const; 64 bool is_pipe_suitable() const; 65 66 friend bool sgls_eq_off(const scat_gath_list &left, int l_e_ind, 67 int l_blk_off, 68 const scat_gath_list &right, int r_e_ind, 69 int r_blk_off, bool allow_partial); 70 71 bool load_from_cli(const char * cl_p, bool b_vb); 72 bool load_from_file(const char * file_name, bool def_hex, bool flexible, 73 bool b_vb); 74 int append_1or(int64_t extra_blks, int64_t start_lba); 75 int append_1or(int64_t extra_blks); 76 77 void dbg_print(bool skip_meta, const char * id_str, bool to_stdout, 78 bool show_sgl) const; 79 80 // calculates and sets following bool-s and int64_t-s 81 void sum_scan(const char * id_str, bool show_sgl, bool b_verbose); 82 83 void set_weaker_linearity(enum sgl_linearity_e lin); 84 enum sgl_linearity_e linearity; 85 const char * linearity_as_str() const; 86 87 bool sum_hard; // 'num' in last element of 'sgl' is > 0 88 int m_errno; // OS failure errno 89 int64_t high_lba_p1; // highest LBA plus 1, next write from and above 90 int64_t lowest_lba; // initialized to 0 91 int64_t sum; // of all 'num' elements in 'sgl' 92 93 friend int diff_between_iters(const class scat_gath_iter & left, 94 const class scat_gath_iter & right); 95 96 private: 97 friend class scat_gath_iter; 98 99 bool file2sgl_helper(FILE * fp, const char * fnp, bool def_hex, 100 bool flexible, bool b_vb); 101 102 std::vector<scat_gath_elem> sgl; // an array on heap [0..num_elems()) 103 }; 104 105 106 class scat_gath_iter { 107 public: 108 explicit scat_gath_iter(const scat_gath_list & my_scat_gath_list); 109 scat_gath_iter(const scat_gath_iter & src) = default; 110 scat_gath_iter& operator=(const scat_gath_iter&) = delete; 111 ~scat_gath_iter() = default; 112 113 int64_t current_lba() const; 114 int64_t current_lba_rem_num(int & rem_num) const; 115 class scat_gath_elem current_elem() const; 116 bool at_end() const; 117 bool is_sgl_linear() const; // the whole list 118 // Should return 1 or more unless max_n<=0 or at_end() 119 int linear_for_n_blks(int max_n) const; 120 121 bool set_by_blk_idx(int64_t _blk_idx); 122 // add/sub blocks return true if they reach EOL/start, else false 123 bool add_blks(uint64_t blk_count); 124 bool sub_blks(uint64_t blk_count); 125 126 void dbg_print(const char * id_str, bool to_stdout, int verbose) const; 127 128 friend int diff_between_iters(const class scat_gath_iter & left, 129 const class scat_gath_iter & right); 130 131 friend bool sgls_eq_from_iters(const class scat_gath_iter & left, 132 const class scat_gath_iter & right, 133 bool allow_partial); 134 135 private: 136 const scat_gath_list &sglist; 137 138 // dual representation: either it_el_ind,it_blk_off or blk_idx 139 int it_el_ind; // refers to sge==sglist[it_el_ind] 140 int it_blk_off; // refers to LBA==(sge.lba + it_blk_off) 141 int64_t blk_idx; // in range: [0 .. sglist.sum) 142 bool extend_last; 143 }; 144