aboutsummaryrefslogtreecommitdiff
path: root/testing/sg_scat_gath.h
blob: d316a7b13f2c20a960ade9b2d226f3d85cea37cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright (c) 2014-2020 Douglas Gilbert.
 * All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the BSD_LICENSE file.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

// C standard headers
#include <stdio.h>
#include <stdint.h>
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>

// C++ standard headers
#include <vector>

// This file is a C++ header file


#define SG_SGL_MAX_ELEMENTS 16384

#define SG_COUNT_INDEFINITE (-1)
#define SG_LBA_INVALID SG_COUNT_INDEFINITE

// Sizing matches largest SCSI READ and WRITE commands plus those of Unix
// read(2)s and write(2)s. User can give larger than 31 bit 'num's but they
// are split into several consecutive elements.
class scat_gath_elem {
public:
    uint64_t lba;       // of start block
    uint32_t num;       // number of blocks from and including start block

    void make_bad() { lba = UINT64_MAX; num = UINT32_MAX; }
    bool is_bad() const { return (lba == UINT64_MAX && num == UINT32_MAX); }
};

// Consider "linearity" as a scatter gather list property. Elements of this
// of from the strongest form to the weakest.
enum sgl_linearity_e {
    SGL_LINEAR = 0,     // empty list and 0,0 considered linear
    SGL_MONOTONIC,      // since not linear, implies holes
    SGL_MONO_OVERLAP,   // monotonic but same LBA in two or more elements
    SGL_NON_MONOTONIC   // weakest
};


// Holds one scatter gather list and its associated metadata
class scat_gath_list {
public:
    scat_gath_list() : linearity(SGL_LINEAR), sum_hard(false), m_errno(0),
        high_lba_p1(0), lowest_lba(0), sum(0) { }

    scat_gath_list(const scat_gath_list &) = default;
    scat_gath_list & operator=(const scat_gath_list &) = default;
    ~scat_gath_list() = default;

    bool empty() const;
    bool empty_or_00() const;
    int num_elems() const;
    int64_t get_lowest_lba(bool ignore_degen, bool always_last) const;
    int64_t get_low_lba_from_linear() const;
    bool is_pipe_suitable() const;

    friend bool sgls_eq_off(const scat_gath_list &left, int l_e_ind,
                            int l_blk_off,
                            const scat_gath_list &right, int r_e_ind,
                            int r_blk_off, bool allow_partial);

    bool load_from_cli(const char * cl_p, bool b_vb);
    bool load_from_file(const char * file_name, bool def_hex, bool flexible,
                        bool b_vb);
    int append_1or(int64_t extra_blks, int64_t start_lba);
    int append_1or(int64_t extra_blks);

    void dbg_print(bool skip_meta, const char * id_str, bool to_stdout,
                   bool show_sgl) const;

    // calculates and sets following bool-s and int64_t-s
    void sum_scan(const char * id_str, bool show_sgl, bool b_verbose);

    void set_weaker_linearity(enum sgl_linearity_e lin);
    enum sgl_linearity_e linearity;
    const char * linearity_as_str() const;

    bool sum_hard;      // 'num' in last element of 'sgl' is > 0
    int m_errno;        // OS failure errno
    int64_t high_lba_p1;  // highest LBA plus 1, next write from and above
    int64_t lowest_lba; // initialized to 0
    int64_t sum;        // of all 'num' elements in 'sgl'

    friend int diff_between_iters(const class scat_gath_iter & left,
                                  const class scat_gath_iter & right);

private:
    friend class scat_gath_iter;

    bool file2sgl_helper(FILE * fp, const char * fnp, bool def_hex,
                         bool flexible, bool b_vb);

    std::vector<scat_gath_elem> sgl;  // an array on heap [0..num_elems())
};


class scat_gath_iter {
public:
    explicit scat_gath_iter(const scat_gath_list & my_scat_gath_list);
    scat_gath_iter(const scat_gath_iter & src) = default;
    scat_gath_iter&  operator=(const scat_gath_iter&) = delete;
    ~scat_gath_iter() = default;

    int64_t current_lba() const;
    int64_t current_lba_rem_num(int & rem_num) const;
    class scat_gath_elem current_elem() const;
    bool at_end() const;
    bool is_sgl_linear() const; // the whole list
    // Should return 1 or more unless max_n<=0 or at_end()
    int linear_for_n_blks(int max_n) const;

    bool set_by_blk_idx(int64_t _blk_idx);
    // add/sub blocks return true if they reach EOL/start, else false
    bool add_blks(uint64_t blk_count);
    bool sub_blks(uint64_t blk_count);

    void dbg_print(const char * id_str, bool to_stdout, int verbose) const;

    friend int diff_between_iters(const class scat_gath_iter & left,
                                  const class scat_gath_iter & right);

    friend bool sgls_eq_from_iters(const class scat_gath_iter & left,
                                   const class scat_gath_iter & right,
                                   bool allow_partial);

private:
    const scat_gath_list &sglist;

    // dual representation: either it_el_ind,it_blk_off or blk_idx
    int it_el_ind;      // refers to sge==sglist[it_el_ind]
    int it_blk_off;     // refers to LBA==(sge.lba + it_blk_off)
    int64_t blk_idx;    // in range: [0 .. sglist.sum)
    bool extend_last;
};