github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/pkg/smart/ataidentify.go (about) 1 /* 2 Copyright 2018 The OpenEBS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package smart 15 16 import ( 17 "fmt" 18 ) 19 20 // swapByteOrder swaps the order of every second byte in a byte slice and 21 // modifies the slice in place. 22 func (d *ATACSPage) swapByteOrder(b []byte) []byte { 23 tmp := make([]byte, len(b)) 24 25 for i := 0; i < len(b); i += 2 { 26 tmp[i], tmp[i+1] = b[i+1], b[i] 27 } 28 return tmp 29 } 30 31 // getSerialNumber returns the serial number of a disk device 32 // using an ATA IDENTIFY command. 33 func (d *ATACSPage) getSerialNumber() []byte { 34 // Needed a byte swap since each pair of bytes in an ATA string is swapped 35 // word 0 | offset 0 -> second character, offset 1 -> First character and so on. 36 return d.swapByteOrder(d.SerialNumber[:]) 37 } 38 39 // getWWN returns the worldwide unique name for a disk 40 // The World Wide Name (WWN) uses the NAA IEEE Registered designator format 41 // defined in SPC-5 with the NAA field set to 5h. 42 func (d *ATACSPage) getWWN() string { 43 // NAA field indicates the format of the world wide name 44 NAA := d.WWN[0] >> 12 45 // IEEE OUI field shall contain the 24-bit canonical form company 46 // identifier (i.e., OUI) that the IEEE has assigned to the device manufacturer 47 IEEEOUI := (uint32(d.WWN[0]&0x0fff) << 12) | (uint32(d.WWN[1]) >> 4) 48 // UNIQUE ID field shall contain a value assigned by the device manufacturer 49 // that is unique for the device within the OUI domain 50 UniqueID := ((uint64(d.WWN[1]) & 0xf) << 32) | (uint64(d.WWN[2]) << 16) | uint64(d.WWN[3]) 51 52 return fmt.Sprintf("%x %06x %09x", NAA, IEEEOUI, UniqueID) 53 } 54 55 // getSectorSize returns logical and physical sector sizes of a disk 56 func (d *ATACSPage) getSectorSize() (uint32, uint32) { 57 // By default, we are assuming the physical and logical sector size to be 512 58 // based on further check conditions, it would be altered. 59 var LogSec, PhySec uint32 = 512, 512 60 61 if (d.SectorSize & 0xc000) != 0x4000 { 62 return LogSec, PhySec 63 } 64 // TODO : Add support for Long Logical/Physical Sectors (LLS/LPS) 65 if (d.SectorSize & 0x2000) != 0x0000 { 66 // Physical sector size is multiple of logical sector size 67 PhySec <<= (d.SectorSize & 0x0f) 68 } 69 return LogSec, PhySec 70 } 71 72 // getATAMajorVersion returns the ATA major version of a disk using an ATA IDENTIFY command. 73 func (d *ATACSPage) getATAMajorVersion() (s string) { 74 if (d.MajorVer == 0) || (d.MajorVer == 0xffff) { 75 return "This device does not report ATA major version" 76 } 77 // ATA Major version word is a bitmask, hence we will get the most significant bit 78 // of this word and then do a map lookup 79 majorVer := MSignificantBit(uint(d.MajorVer)) 80 if s, ok := ataMajorVersions[majorVer]; ok { 81 return s 82 } 83 return "unknown" 84 } 85 86 // getATAMinorVersion returns the ATA minor version using an ATA IDENTIFY command. 87 func (d *ATACSPage) getATAMinorVersion() string { 88 if (d.MinorVer == 0) || (d.MinorVer == 0xffff) { 89 return "This device does not report ATA minor version" 90 } 91 // Since ATA minor version word is not a bitmask, we simply do a map lookup here 92 if s, ok := ataMinorVersions[d.MinorVer]; ok { 93 return s 94 } 95 return "unknown" 96 } 97 98 // ataTransport returns the type of ata Transport being 99 // used such as serial ATA, parallel ATA, etc. 100 func (d *ATACSPage) ataTransport() (s string) { 101 if (d.AtaTransportMajor == 0) || (d.AtaTransportMajor == 0xffff) { 102 s = "This device does not report Transport" 103 return 104 } 105 switch d.AtaTransportMajor >> 12 { 106 case 0x0: 107 s = "Parallel ATA" // parallel ata transport 108 case 0x1: 109 s = d.IdentifySerialATAType() // identify the type of serial ata as it is a serial ata transport 110 case 0xe: 111 s = fmt.Sprintf("PCIe (%#03x)", d.AtaTransportMajor&0x0fff) 112 default: 113 s = fmt.Sprintf("Unknown (%#04x)", d.AtaTransportMajor) 114 } 115 return 116 } 117 118 // IdentifySerialATAType identifies the type of SATA transport being used by a disk 119 func (d *ATACSPage) IdentifySerialATAType() (s string) { 120 s = "Serial ATA" 121 // Get the most significant bit of the ata transport major word as it is a bitmask 122 // and then get the serial ata transport type based on the value 123 transportMajor := MSignificantBit(uint(d.AtaTransportMajor & 0x0fff)) 124 // Lookup in the map for the type of serial ata transport based on key 125 if serialATAType, ok := serialATAType[transportMajor]; ok { 126 s += serialATAType 127 return s 128 } 129 s += fmt.Sprintf(" SATA (%#03x)", d.AtaTransportMajor&0x0fff) 130 return s 131 }