xref: /aosp_15_r20/external/sg3_utils/testing/sg_scat_gath.h (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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