...

Source file src/github.com/prometheus/procfs/sysfs/class_sas_phy.go

Documentation: github.com/prometheus/procfs/sysfs

     1  // Copyright 2021 The Prometheus Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  //go:build linux
    15  // +build linux
    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   // /sys/class/sas_phy/<Name>
    33  	SASAddress                 string   // /sys/class/sas_phy/<Name>/sas_address
    34  	SASPort                    string   // /sys/class/sas_phy/<Name>/device/ports
    35  	DeviceType                 string   // /sys/class/sas_phy/<Name>/device_type
    36  	InitiatorPortProtocols     []string // /sys/class/sas_phy/<Name>/initiator_port_protocols
    37  	InvalidDwordCount          int      // /sys/class/sas_phy/<Name>/invalid_dword_count
    38  	LossOfDwordSyncCount       int      // /sys/class/sas_phy/<Name>/loss_of_dword_sync_count
    39  	MaximumLinkrate            float64  // /sys/class/sas_phy/<Name>/maximum_linkrate
    40  	MaximumLinkrateHW          float64  // /sys/class/sas_phy/<Name>/maximum_linkrate_hw
    41  	MinimumLinkrate            float64  // /sys/class/sas_phy/<Name>/minimum_linkrate
    42  	MinimumLinkrateHW          float64  // /sys/class/sas_phy/<Name>/minimum_linkrate_hw
    43  	NegotiatedLinkrate         float64  // /sys/class/sas_phy/<Name>/negotiated_linkrate
    44  	PhyIdentifier              string   // /sys/class/sas_phy/<Name>/phy_identifier
    45  	PhyResetProblemCount       int      // /sys/class/sas_phy/<Name>/phy_reset_problem_count
    46  	RunningDisparityErrorCount int      // /sys/class/sas_phy/<Name>/running_disparity_error_count
    47  	TargetPortProtocols        []string // /sys/class/sas_phy/<Name>/target_port_protocols
    48  }
    49  
    50  type SASPhyClass map[string]*SASPhy
    51  
    52  // SASPhyClass parses entries in /sys/class/sas_phy.
    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  // Parse a single sas_phy.
    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  // parseLinkRate turns the kernel's SAS linkrate values into floats.
   148  // The kernel returns values like "12.0 Gbit".  Valid speeds are
   149  // currently 1.5, 3.0, 6.0, 12.0, and up.  This is a float to cover
   150  // the 1.5 Gbps case.  A value of 0 is returned if the speed can't be
   151  // parsed.
   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  // GetByName returns the SASPhy with the provided name.
   162  func (spc *SASPhyClass) GetByName(name string) *SASPhy {
   163  	return (*spc)[name]
   164  }
   165  

View as plain text