...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package sysfs
18
19 import (
20 "fmt"
21 "os"
22 "path/filepath"
23 "strconv"
24 "strings"
25
26 "github.com/prometheus/procfs/internal/util"
27 )
28
29 const sasPhyClassPath = "class/sas_phy"
30
31 type SASPhy struct {
32 Name string
33 SASAddress string
34 SASPort string
35 DeviceType string
36 InitiatorPortProtocols []string
37 InvalidDwordCount int
38 LossOfDwordSyncCount int
39 MaximumLinkrate float64
40 MaximumLinkrateHW float64
41 MinimumLinkrate float64
42 MinimumLinkrateHW float64
43 NegotiatedLinkrate float64
44 PhyIdentifier string
45 PhyResetProblemCount int
46 RunningDisparityErrorCount int
47 TargetPortProtocols []string
48 }
49
50 type SASPhyClass map[string]*SASPhy
51
52
53 func (fs FS) SASPhyClass() (SASPhyClass, error) {
54 path := fs.sys.Path(sasPhyClassPath)
55
56 dirs, err := os.ReadDir(path)
57 if err != nil {
58 return nil, err
59 }
60
61 spc := make(SASPhyClass, len(dirs))
62
63 for _, d := range dirs {
64 phy, err := fs.parseSASPhy(d.Name())
65 if err != nil {
66 return nil, err
67 }
68
69 spc[phy.Name] = phy
70 }
71
72 return spc, nil
73 }
74
75
76 func (fs FS) parseSASPhy(name string) (*SASPhy, error) {
77 phy := SASPhy{Name: name}
78
79 phypath := fs.sys.Path(filepath.Join(sasPhyClassPath, name))
80 phydevicepath := filepath.Join(phypath, "device")
81
82 link, err := os.Readlink(filepath.Join(phydevicepath, "port"))
83
84 if err == nil {
85 if sasPortDeviceRegexp.MatchString(filepath.Base(link)) {
86 phy.SASPort = filepath.Base(link)
87 }
88 }
89
90 files, err := os.ReadDir(phypath)
91 if err != nil {
92 return nil, err
93 }
94 for _, f := range files {
95 name := filepath.Join(phypath, f.Name())
96 fileinfo, _ := os.Stat(name)
97 if fileinfo.Mode().IsRegular() {
98 value, err := util.SysReadFile(name)
99 if err != nil {
100 if os.IsPermission(err) {
101 continue
102 }
103 return nil, fmt.Errorf("failed to read file %q: %w", name, err)
104 }
105
106 vp := util.NewValueParser(value)
107 switch f.Name() {
108 case "sas_address":
109 phy.SASAddress = value
110 case "device_type":
111 phy.DeviceType = value
112 case "initiator_port_protocols":
113 phy.InitiatorPortProtocols = strings.Split(value, ", ")
114 case "invalid_dword_count":
115 phy.InvalidDwordCount = vp.Int()
116 case "loss_of_dword_sync_count":
117 phy.LossOfDwordSyncCount = vp.Int()
118 case "maximum_linkrate":
119 phy.MaximumLinkrate = parseLinkrate(value)
120 case "maximum_linkrate_hw":
121 phy.MaximumLinkrateHW = parseLinkrate(value)
122 case "minimum_linkrate":
123 phy.MinimumLinkrate = parseLinkrate(value)
124 case "minimum_linkrate_hw":
125 phy.MinimumLinkrateHW = parseLinkrate(value)
126 case "negotiated_linkrate":
127 phy.NegotiatedLinkrate = parseLinkrate(value)
128 case "phy_identifier":
129 phy.PhyIdentifier = value
130 case "phy_reset_problem_count":
131 phy.PhyResetProblemCount = vp.Int()
132 case "running_disparity_error_count":
133 phy.RunningDisparityErrorCount = vp.Int()
134 case "target_port_protocols":
135 phy.TargetPortProtocols = strings.Split(value, ", ")
136 }
137
138 if err := vp.Err(); err != nil {
139 return nil, err
140 }
141 }
142 }
143
144 return &phy, nil
145 }
146
147
148
149
150
151
152 func parseLinkrate(value string) float64 {
153 f := strings.Split(value, " ")[0]
154 gb, err := strconv.ParseFloat(f, 64)
155 if err != nil {
156 return 0
157 }
158 return gb
159 }
160
161
162 func (spc *SASPhyClass) GetByName(name string) *SASPhy {
163 return (*spc)[name]
164 }
165
View as plain text