Назад | Перейти на главную страницу

Ошибки Linux ATA: перевод на имя устройства?

Когда Linux-сервер получает ошибку ATA, он записывает ее в системный журнал с сообщением, идентифицирующим диск как «ata% d.00». Как мне перевести это на имя устройства (например, /dev/sdb)? Я чувствую, что это должно быть тривиально, но я не могу этого понять.

Питер вдохновил меня написать продвинутый скрипт (let), который может даже обнаруживать USB-накопители (вместо вывода таких глупых вещей, как «ata0.00»). В отличие от сценария Питера, вы также получите дополнительный номер (как в 4.01), если у вас есть более одного устройства на одном контроллере, соответственно. канал. Результат будет именно таким, как вы его получили. syslog. Проверено. Очень хорошо работает на моем компьютере с Debian, хотя всегда есть много улучшений (например, слишком неуклюжие регулярные выражения). Но ДЕРЖИТЕ! Кажущееся слишком большое количество экранированных символов, которые вы можете найти в моих регулярных выражениях, вызвано соображениями совместимости! Вы не можете предположить, что GNU sed со всеми, поэтому я специально отказался от расширенных регулярных выражений.

ОБНОВЛЕНИЯ
(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"

смотреть на /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".

Я предпочитаю скриптлеты длинным пояснениям. Это работает на моем компьютере с 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

На самом деле это довольно сложно. Хотя можно с уверенностью предположить, что «идентификатор scsi» - это «идентификатор SATA минус один», я предпочитаю быть действительно безопасным и проверить 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. найти PCI id контроллера SATA

    # lspci | grep -i sata
    00:1f.2 SATA controller: Intel Corporation 631xESB/632xESB SATA AHCI Controller (rev 09)
    
  2. найти соответствующий уникальный идентификатор:

    # 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. так это на 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
    
  4. вот наше устройство, мы можем (необязательно) найти серийный номер, чтобы вытащить это устройство оттуда (или проверить кабели или что-то еще), прежде чем наш RAID-массив полностью выйдет из строя:

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

И вы сделали!

Попробуй это:

# 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 указаны.

Только если ваша система 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

Результат содержит все устройства нижнего уровня и соответствующие блочные устройства на одной линии.

У меня была такая же проблема, и я смог идентифицировать диски, проверив 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

Самый простой способ - просмотреть журнал ядра при загрузке, поскольку имена дисководов смешиваются из разных источников (например, USB-накопители) или назначаются в зависимости от типа устройства (например, cdrom может быть scdX вместо этого, и все имеет sgX). На практике, если вы не смешали разные типы шин (например, SATA + USB), устройством ata с наименьшим номером будет sda, если это не устройство cdrom.

В зависимости от вашей системы, это может быть обнаружено путем блуждания по sysfs. В моей системе ls -l /sys/dev/block показывает, что 8:0 (major: minor из / dev entry) указывает на /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 должен быть сопоставлен с "ID" в папке host: channel: ID: LUN из /sys/dev/block/ листинг. Если у вас несколько ataX/ и hostY/ папки в той же папке устройства PCI, затем я подозреваемый что папка ataX с наименьшим номером соответствует папке hostY с наименьшим номером.

В /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

Приведенный ниже сценарий даст вам такое приятное резюме:

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 имя устройства, размер, модель, s / n и pci и Ата числа. Вышеупомянутый 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)