Linux ATA错误:转换为设备名称?


36

当Linux系统出现ATA错误时,它将通过一条消息将其记录为ata%d.00,以进行系统日志记录。如何将其转换为设备名称(例如/dev/sdb)?我觉得这应该是微不足道的,但我无法弄清楚。


1
另请参阅我对Unix-SE上类似问题的回答:unix.stackexchange.com/a/13988/1131
maxschlepzig

Answers:


28

彼得启发我写了一个高级脚本(let),它甚至可以检测USB记忆棒(而不是输出“ ata0.00”之类的愚蠢东西)。与Peter的脚本相反,如果在同一控制器上有多个设备,则还将获得子编号(如4.01)。渠道。输出将完全与您获得的一样syslog。经过测试。尽管总会有很多改进(例如,正则表达式太笨拙),但在我的Debian机器上工作得很好。但是,请坚持!您可能在我的正则表达式中发现的转义字符数量似乎过多,仅出于兼容性原因!您不能sed与所有人一起使用GNU ,这就是为什么我没有故意扩展regexp的原因。

更新
(1)将不再解析ls输出。(糟糕!)既然大家都知道:不要解析ls。
(2)现在也可以在只读环境中使用。
(3)通过从该闲聊的建议启发这里我已成功地再次拿到sed的报表方式不太复杂。

#!/bin/bash
# note: inspired by Peter
#
# *UPDATE 1* now we're no longer parsing ls output
# *UPDATE 2* now we're using an array instead of the <<< operator, which on its
# part insists on a writable /tmp directory: 
# restricted environments with read-only access often won't allow you that

# save original IFS
OLDIFS="$IFS"

for i in /sys/block/sd*; do 
 readlink $i |
 sed 's^\.\./devices^/sys/devices^ ;
      s^/host[0-9]\{1,2\}/target^ ^ ;
      s^/[0-9]\{1,2\}\(:[0-9]\)\{3\}/block/^ ^' \
 \
  |
  while IFS=' ' read Path HostFull ID
  do

     # OLD line: left in for reasons of readability 
     # IFS=: read HostMain HostMid HostSub <<< "$HostFull"

     # NEW lines: will now also work without a hitch on r/o environments
     IFS=: h=($HostFull)
     HostMain=${h[0]}; HostMid=${h[1]}; HostSub=${h[2]}

     if echo $Path | grep -q '/usb[0-9]*/'; then
       echo "(Device $ID is not an ATA device, but a USB device [e. g. a pen drive])"
     else
       echo $ID: ata$(< "$Path/host$HostMain/scsi_host/host$HostMain/unique_id").$HostMid$HostSub
     fi

  done

done

# restore original IFS
IFS="$OLDIFS"

仅提醒您,脚本可能不会显示有问题的设备。我的ata6错误与softreset失败(第一次FIS失败)(次要问题)列出的设备有关,并且它不存在。如果您知道PC中有4个磁盘,而仅显示3个,则可能是原因。
肯德里克

1
@Kendrick好吧,在这种情况下,我不会怪脚本。因为如果您知道内核驱动程序是如何工作的,那么,这将比您更加清楚:)已知一旦“问题”足够严重,内核子系统驱动程序就会放弃。这表明,对于具有UDMA功能的驱动器,它可能会导致多次驱动器复位,并(最终)尝试在PIO模式下进行驱动器操作。但是,如果这也证明太不稳定(各种计时错误等),驾驶员将对驱动器说“走开”。对于旧的PATA驱动器,这意味着必须强制进行冷重启才能再次显示驱动器。
语法错误

我并不是要怪罪脚本。只是提醒人们为什么可能会丢失它:)愚蠢的Flakey Seagate控制器板让您很难理解发生了什么。
肯德里克

@Kendrick你是在告诉我。:)好吧,在我的书中,希捷绝对不应该买断三星。非常喜欢后一种驱动器(当时三星仍从事大容量存储业务),以及他们出色的支持团队。现在,希捷接管了所有这一切……和……哦。
语法错误,2015年

11

看一下/proc/scsi/scsi,它看起来像这样:

$ cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: ST3250823AS      Rev: 3.03
  Type:   Direct-Access                    ANSI SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: ST3750528AS      Rev: CC44
  Type:   Direct-Access                    ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: ST3750330AS      Rev: SD1A
  Type:   Direct-Access                    ANSI SCSI revision: 05
Host: scsi10 Channel: 00 Id: 00 Lun: 00
  Vendor: WDC WD20 Model: EARS-00MVWB0     Rev:     
  Type:   Direct-Access                    ANSI SCSI revision: 02

scsi0 id 0是sda和ata1.00,scsi1 id 0是sdb和ata2.00,依此类推。

还要查看/var/log/dmesg,它显示了ata驱动程序的加载信息,并使您的情况更加清楚。查找以“ libata”开头的行。


8
您可能还需要使用'lsscsi'-这样输出的输出会更加人性化-例如[0:0:0:0] cd / dvd TSSTcorp CDDVDW SH-S202H SB00 / dev / sr0 [2:0:0:0 ]磁盘ATA ST3500630AS 3.AA / dev / sda [3:0:0:0]磁盘ATA WDC WD5000AAKS-0 01.0 / dev / sdb(在此服务器上,运行3.2.x内核,没有/ proc / scsi *)(对不起,我似乎无法弄清楚如何将上述格式设置为可读性)
David Goodwin

1
这应该是答案,而不是评论。从一台机器上读取有用,快速且易于阅读的内容,然后在出现问题的另一台机器上打字。
年长者极客

10

我更喜欢scriptlet而不是冗长的解释。这适用于我的Ubuntu盒子。根据自己的喜好添加评论:

# on Ubuntu get ata ID for block devices sd*
ls -l /sys/block/sd* \
| sed -e 's^.*-> \.\.^/sys^' \
       -e 's^/host^ ^'        \
       -e 's^/target.*/^ ^'   \
| while read Path HostNum ID
  do
     echo ${ID}: $(cat $Path/host$HostNum/scsi_host/host$HostNum/unique_id)
  done

您的脚本比答案要吓人一些,主要是因为我可以看清整个内容。
isaaclw 2014年

1
简化一点(在Centos上对我ls -l /sys/block/sd* | sed -e 's@.*-> \.\..*/ata@/ata@' -e 's@/host@ @' -e 's@/target.*/@ @'
有用

9

这实际上很棘手。虽然可以安全地假设“ scsi ID”是“ SATA ID减1”,但我还是比较安全,并检查一下unique_id我基于SATA标识符(根据本帖子)。

我的错误是:

[6407990.328987] ata4.00: exception Emask 0x10 SAct 0x1 SErr 0x280100 action 0x6 frozen
[6407990.336824] ata4.00: irq_stat 0x08000000, interface fatal error
[6407990.343012] ata4: SError: { UnrecovData 10B8B BadCRC }
[6407990.348395] ata4.00: failed command: READ FPDMA QUEUED
[6407990.353819] ata4.00: cmd 60/20:00:28:c2:39/00:00:0c:00:00/40 tag 0 ncq 16384 in
[6407990.353820]          res 40/00:00:28:c2:39/00:00:0c:00:00/40 Emask 0x10 (ATA bus error)
[6407990.369618] ata4.00: status: { DRDY }
[6407990.373504] ata4: hard resetting link
[6407995.905574] ata4: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[6407995.976946] ata4.00: configured for UDMA/133
[6407995.976961] ata4: EH complete

所以我的程序来找出是什么ata4

  1. 查找SATA控制器的PCI ID

    # lspci | grep -i sata
    00:1f.2 SATA controller: Intel Corporation 631xESB/632xESB SATA AHCI Controller (rev 09)
    
  2. 找到匹配的唯一ID:

    # grep 4 /sys/devices/pci0000:00/0000:00:1f.2/*/*/*/unique_id
    /sys/devices/pci0000:00/0000:00:1f.2/host3/scsi_host/host3/unique_id:4
    
  3. 因此它位于on scsi_host/host3,我们可以将其翻译为3:x:x:x,我们可以对其进行grep dmesg查找以了解更多信息:

    # dmesg | grep '3:.:.:.'
    [    2.140616] scsi 3:0:0:0: Direct-Access     ATA      ST3250310NS      SN06 PQ: 0 ANSI: 5
    [    2.152477] sd 3:0:0:0: [sdd] 488397168 512-byte logical blocks: (250 GB/232 GiB)
    [    2.152551] sd 3:0:0:0: [sdd] Write Protect is off
    [    2.152554] sd 3:0:0:0: [sdd] Mode Sense: 00 3a 00 00
    [    2.152576] sd 3:0:0:0: [sdd] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
    [    2.157004] sd 3:0:0:0: [sdd] Attached SCSI disk
    [    2.186897] sd 3:0:0:0: Attached scsi generic sg3 type 0
    
  4. 这是我们的设备,在RAID阵列完全失效之前,我们可以(可选)找到将设备从那里拿出的序列号(或检查电缆连接等):

    # hdparm -i /dev/sdd | grep Serial
     Model=ST3250310NS, FwRev=SN06, SerialNo=9SF19GYA
    

大功告成!


7

尝试这个:

# find -L /sys/bus/pci/devices/*/ata*/host*/target* -maxdepth 3 -name "sd*" 2>/dev/null | egrep block |egrep --colour '(ata[0-9]*)|(sd.*)'

我从不了解dmesg-有些行是关于“ ata4”的,有些行是关于“ scsi”或sdc的,但是没有人分配“ ata4 ... .sdc”,显示的命令找到了/ sys / bus /路径,其中ata4和sdc被指定。


5

我遇到了同样的问题,并且能够通过检查dmesg来识别驱动器。在这里,您可以看到控制器标识符(正确的术语??)和磁盘型号。然后使用ls -l / dev / disk / by-id将型号匹配到/ dev / sda(或其他)。另外,我喜欢“磁盘工具”来获取此信息。注意:这仅在磁盘具有不同型号时才有效,否则,您将无法在两者之间进行区分。

>dmesg |grep ata
...
[   19.178040] ata2.00: ATA-8: WDC WD2500BEVT-00A23T0, 01.01A01, max UDMA/133
[   19.178043] ata2.00: 488397168 sectors, multi 16: LBA48 NCQ (depth 31/32), AA
[   19.179376] ata2.00: configured for UDMA/133
[   19.264152] ata3.00: ATA-8: WDC WD3200BEVT-00ZCT0, 11.01A11, max UDMA/133
[   19.264154] ata3.00: 625142448 sectors, multi 16: LBA48 NCQ (depth 31/32), AA
[   19.266767] ata3.00: configured for UDMA/133
...

>ls -l /dev/disk/by-id
lrwxrwxrwx 1 root root  9 Feb 18 12:17 ata-WDC_WD2500BEVT-00A23T0_WD-WXE1A7131446 -> ../../sda
lrwxrwxrwx 1 root root 10 Feb 18 11:48 ata-WDC_WD2500BEVT-00A23T0_WD-WXE1A7131446-part1 -> ../../sda1
lrwxrwxrwx 1 root root  9 Feb 18 12:17 ata-WDC_WD3200BEVT-00ZCT0_WD-WXHZ08045183 -> ../../sdb
lrwxrwxrwx 1 root root 10 Feb 18 11:48 ata-WDC_WD3200BEVT-00ZCT0_WD-WXHZ08045183-part1 -> ../../sdb1

2

最简单的方法是从启动中查看内核日志,因为驱动器设备名称是从各种来源(例如USB驱动器)混入的,或者是根据设备类型分配的(即cdrom可能是scdX,而所有内容都有sgX) )。实际上,除非您混用了各种总线(例如SATA + USB),否则编号最低的ata设备将是sda,除非它是cdrom设备。

根据您的系统,它可能会因在sysfs上徘徊而占卜。在我的系统上ls -l /sys/dev/block显示8:0(/ dev条目中的main:minor)指向/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda 同样,ls -l /sys/class/ata_port表明ata1指向/sys/devices/pci0000:00/0000:00:1f.2/ata1/ata_port/ata1同一PCI子设备上的指向。

由于我使用SATA,并且每个端口上只有一个驱动器,因此我可以推断出ata1.00 = sda。我所有的驱动器都是.00,我怀疑如果使用端口倍增器,我的驱动器将得到.01,.02,.03等。查看其他人的日志PATA控制器将.00和.01用作主服务器和从属服务器。 ,并根据其日志(如果您有ataX.01),将.01映射到列表中host:channel:ID:LUN文件夹中的“ ID” /sys/dev/block/。如果有多个ataX/hostY/文件夹相同的PCI设备的文件夹,然后我怀疑最低编号ataX文件夹相匹配的最低编号HOSTY文件夹。


2

在中/sys/class/ata_port/ata${n}/device/,您可以看到一个host${x}文件夹。例如,在我的机器上:

gibby ~ # ls /sys/class/ata_port/ata1/device/
ata_port  host0  link1  power  uevent
gibby ~ # ls /sys/class/ata_port/ata2/device/
ata_port  host1  link2  power  uevent
gibby ~ # lsscsi
[0:0:0:0]    disk    ATA      WDC WD1002FAEX-0 1D05  /dev/sda
[1:0:0:0]    disk    ATA      WDC WD2001FFSX-6 0A81  /dev/sdb
[2:0:0:0]    disk    ATA      WDC WD1002FAEX-0 1D05  /dev/sdc
[3:0:0:0]    disk    ATA      WDC WD2001FFSX-6 0A81  /dev/sdd
[5:0:0:0]    disk    ATA      SAMSUNG MZ7TD256 2L5Q  /dev/sde

${x}host${x}是指在那个第一个数字[0:0:0:0]。所以对我来说ata1是指host0其也可以在SCSI形式来表示0:*

gibby ~ # lsscsi 0:\*
[0:0:0:0]    disk    ATA      WDC WD1002FAEX-0 1D05  /dev/sda

0

下面的脚本将为您提供一个不错的摘要,如下所示:

sda [  180.0 GB] INTEL SSDSC2BW180A4, BTDA4052066D1802GN pci0000:00/0000:00:11.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
sdb [ 1000.2 GB] WDC WD1000DHTZ-04N21V1, WD-WXM1E83CNTX5 pci0000:00/0000:00:11.0/ata3/host2/target2:0:0/2:0:0:0/block/sdc
sdc [ ------ GB] -- pci0000:00/0000:00:12.2/usb1/1-5/1-5:1.0/host6/target6:0:0/6:0:0:0/block/sdf

因此,每个驱动器一行中有sdX设备名称,大小型号序列号pciata号。上面的sdc对应于未插入卡的USB SD卡读取器。因此,----代替了真实信息。

#!/bin/bash
BLKDEVS=`ls -l /sys/block/sd*|sed -e 's/^.* -> //' -e 's/^...devices.//'`
echo $BLKDEVS|tr \  \\n |sort| \
while read DISK ; do
    SD=`echo $DISK|sed -e 's/^.*\///'`
    INFO=`hdparm -i /dev/$SD 2>/dev/null|grep Model=|sed -e 's/Model=//' -e 's/FwRev=[^ ]*//' -e 's/SerialNo=//'`
    ! [[ $INFO ]] && INFO='--'
    SIZE=`fdisk -l /dev/$SD 2>/dev/null|grep '^Disk .* bytes'|sed -e 's/^[^,]*, \([0-9]*\) bytes$/\1/'`
    if [[ $SIZE ]] ; then
        SIZE=`echo $SIZE|awk '{printf "[%7.1f GB]" , $1/1000/1000/1000}'|tr \  _`
    else
        SIZE='[ ------ GB]'
    fi
    echo $SD $SIZE $INFO $DISK
done

(仅在ubuntu 12.04 / 14.04和CentOS 6上进行了测试)


这如何等于向您展示什么,例如ATA 4.01?
Edward_178118 '16

在示例输出中,您看到sda:... ata1 ...和sdb:... ata3 ....确实sda在ata1上,而sdb在ata2上。自从我编写并在4个不同的主机上对其进行测试以来,我发现HW上面的脚本没有包含对ata的引用。我应该指出dmesg | grep“ ata [0-9]”从未使我失败。
ndemou

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.