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

nel*_*age 43 linux hard-drive

当 Linux 机器收到 ATA 错误时,它会在系统日志中记录一条消息,将磁盘标识为“ata%d.00”。我如何将其转换为设备名称(例如/dev/sdb)?我觉得这应该是微不足道的,但我无法弄清楚。

syn*_*ror 30

Peter 启发我编写了一个高级脚本(let),它甚至可以检测 U 盘(而不是输出诸如“ata0.00”之类的愚蠢内容)。与 Peter 的脚本相反,如果您在同一个控制器上有多个设备,您还将获得子编号(如 4.01)。渠道。输出将与您在syslog. 测试。在我的 Debian 机器上工作得很好,虽然总是有很多改进(例如太笨拙的正则表达式)。但是坚持住!您可能在我的正则表达式中发现的转义字符数量似乎过多,这只是出于兼容性原因!你不能假设sed每个人都使用GNU ,这就是我故意没有扩展正则表达式的原因。

更新
(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"
Run Code Online (Sandbox Code Playgroud)


Phi*_*ack 13

看看/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
Run Code Online (Sandbox Code Playgroud)

scsi0 id 0 是 sda 和 ata1.00,scsi1 id 0 是 sdb 和 ata2.00,等等。

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

  • 您可能还需要使用 'lsscsi' - 这会提供更人性化的输出 - 例如 [0:0:0:0] cd/dvd TSSTcorp CDDVDW SH-S202H SB00 /dev/sr0 [2:0:0:0] ] disk ATA ST3500630AS 3.AA /dev/sda [3:0:0:0] disk ATA WDC WD5000AAKS-0 01.0 /dev/sdb(在这个服务器上,运行3.2.x内核,没有/proc/scsi *)(抱歉,我似乎无法弄清楚如何将任何格式设置为上述内容,以使其可读) (10认同)
  • 这应该是答案而不是评论。有用、快速且易于从一台机器读取并在另一台机器上输入有问题。 (2认同)

小智 11

我更喜欢脚本而不是冗长的解释。这适用于我的 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
Run Code Online (Sandbox Code Playgroud)

  • 稍微简化一下(在 Centos 上对我有用)`ls -l /sys/block/sd* | sed -e 's@.*-&gt; \.\..*/ata@/ata@' -e 's@/host@ @' -e 's@/target.*/@ @'` (2认同)

ana*_*cat 9

这实际上非常棘手。虽然可以安全地假设“scsi ID”是“SATA ID 减一”,但我更愿意真正安全地检查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
Run Code Online (Sandbox Code Playgroud)

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

  1. 找到 SATA 控制器的 PCI id

    # lspci | grep -i sata
    00:1f.2 SATA controller: Intel Corporation 631xESB/632xESB SATA AHCI Controller (rev 09)
    
    Run Code Online (Sandbox Code Playgroud)
  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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 所以它是 on scsi_host/host3,我们可以将其转换为3:x:x:x,我们可以搜索它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
    
    Run Code Online (Sandbox Code Playgroud)
  4. 这是我们的设备,我们可以(可选)找到序列号以在我们的 RAID 阵列完全失败之前将该设备从那里取出(或检查电缆或其他任何东西):

    # hdparm -i /dev/sdd | grep Serial
     Model=ST3250310NS, FwRev=SN06, SerialNo=9SF19GYA
    
    Run Code Online (Sandbox Code Playgroud)

你完成了!


sch*_*eik 9

尝试这个:

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

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

只有当您的 udev 系统确实创建了它时,您才可以简单地输入:

# ls -l /dev/disk/by-path/ 
lrwxrwxrwx 1 root root 2020-06-17 12:01 pci-0000:00:1d.7-usb-0:3:1.0-scsi-0:0:0:0 -> ../../sdc 
lrwxrwxrwx 1 root root 2020-06-17 12:07 pci-0000:00:1f.2-ata-1 -> ../../sda 
lrwxrwxrwx 1 root root 2020-06-17 12:07 pci-0000:00:1f.2-ata-1-part1 -> ../../sda1 
lrwxrwxrwx 1 root root 2020-06-17 12:07 pci-0000:00:1f.2-ata-2 -> ../../sdb
Run Code Online (Sandbox Code Playgroud)

结果包含同一行上的所有低级设备和相应的块设备。


小智 8

我遇到了同样的问题,并且能够通过检查 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
Run Code Online (Sandbox Code Playgroud)