...

Source file src/github.com/prometheus/procfs/sysfs/class_sas_port.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  	"os"
    21  	"path/filepath"
    22  	"regexp"
    23  )
    24  
    25  const sasPortClassPath = "class/sas_port"
    26  
    27  type SASPort struct {
    28  	Name       string   // /sys/class/sas_device/<Name>
    29  	SASPhys    []string // /sys/class/sas_device/<Name>/device/phy-*
    30  	Expanders  []string // /sys/class/sas_port/<Name>/device/expander-*
    31  	EndDevices []string // /sys/class/sas_port/<Name>/device/end_device-*
    32  }
    33  
    34  type SASPortClass map[string]*SASPort
    35  
    36  var (
    37  	sasExpanderDeviceRegexp = regexp.MustCompile(`^expander-[0-9:]+$`)
    38  	sasEndDeviceRegexp      = regexp.MustCompile(`^end_device-[0-9:]+$`)
    39  )
    40  
    41  // SASPortClass parses ports in /sys/class/sas_port.
    42  //
    43  // A SAS port in this context is a collection of SAS PHYs operating
    44  // together.  For example, it's common to have 8-lane SAS cards that
    45  // have 2 external connectors, each of which carries 4 SAS lanes over
    46  // a SFF-8088 or SFF-8644 connector.  While it's possible to split
    47  // those 4 lanes into 4 different cables wired directly into
    48  // individual drives, it's more common to connect them all to a SAS
    49  // expander.  This gives you 4x the bandwidth between the expander and
    50  // the SAS host, and is represented by a sas-port object which
    51  // contains 4 sas-phy objects.
    52  func (fs FS) SASPortClass() (SASPortClass, error) {
    53  	path := fs.sys.Path(sasPortClassPath)
    54  
    55  	dirs, err := os.ReadDir(path)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	spc := make(SASPortClass, len(dirs))
    61  
    62  	for _, d := range dirs {
    63  		port, err := fs.parseSASPort(d.Name())
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  
    68  		spc[port.Name] = port
    69  	}
    70  
    71  	return spc, nil
    72  }
    73  
    74  // Parse a single sas_port.
    75  func (fs FS) parseSASPort(name string) (*SASPort, error) {
    76  	port := SASPort{Name: name}
    77  
    78  	portpath := fs.sys.Path(filepath.Join(sasPortClassPath, name, "device"))
    79  
    80  	dirs, err := os.ReadDir(portpath)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	for _, d := range dirs {
    86  		if sasPhyDeviceRegexp.MatchString(d.Name()) {
    87  			port.SASPhys = append(port.SASPhys, d.Name())
    88  		}
    89  		if sasExpanderDeviceRegexp.MatchString(d.Name()) {
    90  			port.Expanders = append(port.Expanders, d.Name())
    91  		}
    92  		if sasEndDeviceRegexp.MatchString(d.Name()) {
    93  			port.EndDevices = append(port.EndDevices, d.Name())
    94  		}
    95  	}
    96  
    97  	return &port, nil
    98  }
    99  
   100  // GetByName returns the SASPort with the provided name.
   101  func (spc *SASPortClass) GetByName(name string) *SASPort {
   102  	return (*spc)[name]
   103  }
   104  
   105  // GetByPhy finds the SASPort that contains the provided PHY name.
   106  func (spc *SASPortClass) GetByPhy(name string) *SASPort {
   107  	for _, d := range *spc {
   108  		for _, p := range d.SASPhys {
   109  			if p == name {
   110  				return d
   111  			}
   112  		}
   113  	}
   114  	return nil
   115  }
   116  
   117  // GetByExpander finds the SASPort that contains the provided SAS expander name.
   118  func (spc *SASPortClass) GetByExpander(name string) *SASPort {
   119  	for _, d := range *spc {
   120  		for _, e := range d.Expanders {
   121  			if e == name {
   122  				return d
   123  			}
   124  		}
   125  	}
   126  	return nil
   127  }
   128  
   129  // GetByEndDevice finds the SASPort that contains the provided SAS end device name.
   130  func (spc *SASPortClass) GetByEndDevice(name string) *SASPort {
   131  	for _, d := range *spc {
   132  		for _, e := range d.EndDevices {
   133  			if e == name {
   134  				return d
   135  			}
   136  		}
   137  	}
   138  	return nil
   139  }
   140  

View as plain text