storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/smart/nvme.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5   * MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  /*
    21   * This file has been adopted and then modified from Daniel Swarbrick's smart
    22   * project residing at https://github.com/dswarbrick/smart
    23   *
    24   */
    25  
    26  package smart
    27  
    28  import (
    29  	"fmt"
    30  	"math/big"
    31  	"unsafe"
    32  
    33  	"github.com/dswarbrick/smart/ioctl"
    34  	"golang.org/x/sys/unix"
    35  )
    36  
    37  // NVMe admin disk query constants
    38  const (
    39  	NvmeAdminGetLogPage = 0x02
    40  	NvmeAdminIdentify   = 0x06
    41  )
    42  
    43  var (
    44  	nvmeIoctlAdminCmd = ioctl.Iowr('N', 0x41, unsafe.Sizeof(nvmePassthruCommand{}))
    45  )
    46  
    47  // NewNVMeDevice creates a new NVMeDevice struct with name
    48  func NewNVMeDevice(name string) *NVMeDevice {
    49  	return &NVMeDevice{name, -1}
    50  }
    51  
    52  // Open - open device file to find kernel info
    53  func (d *NVMeDevice) Open() (err error) {
    54  	d.fd, err = unix.Open(d.Name, unix.O_RDWR, 0600)
    55  	return err
    56  }
    57  
    58  // Close - closes device file
    59  func (d *NVMeDevice) Close() error {
    60  	return unix.Close(d.fd)
    61  }
    62  
    63  func (d *NVMeDevice) readLogPage(logID uint8, buf *[]byte) error {
    64  	bufLen := len(*buf)
    65  
    66  	if (bufLen < 4) || (bufLen > 0x4000) || (bufLen%4 != 0) {
    67  		return fmt.Errorf("Invalid buffer size")
    68  	}
    69  
    70  	cmd := nvmePassthruCommand{
    71  		opcode:  NvmeAdminGetLogPage,
    72  		nsid:    0xffffffff, // FIXME
    73  		addr:    uint64(uintptr(unsafe.Pointer(&(*buf)[0]))),
    74  		dataLen: uint32(bufLen),
    75  		cdw10:   uint32(logID) | (((uint32(bufLen) / 4) - 1) << 16),
    76  	}
    77  
    78  	return ioctl.Ioctl(uintptr(d.fd), nvmeIoctlAdminCmd, uintptr(unsafe.Pointer(&cmd)))
    79  }
    80  
    81  // le128ToBigInt takes a little-endian 16-byte slice and returns a *big.Int representing it.
    82  func le128ToBigInt(buf [16]byte) *big.Int {
    83  	// Int.SetBytes() expects big-endian input, so reverse the bytes locally first
    84  	rev := make([]byte, 16)
    85  	for x := 0; x < 16; x++ {
    86  		rev[x] = buf[16-x-1]
    87  	}
    88  
    89  	return new(big.Int).SetBytes(rev)
    90  }