Erros de Linux ATA: traduzindo para um nome de dispositivo?

36

Quando uma caixa do Linux obtém um erro ATA, ela registra o syslog com uma mensagem identificando o disco como "ata% d.00". Como eu traduzo isso para um nome de dispositivo (por exemplo /dev/sdb)? Eu sinto que isso deve ser trivial, mas não consigo descobrir.

nelhage
fonte
11
Veja também a minha resposta a uma pergunta semelhante sobre Unix-SE: unix.stackexchange.com/a/13988/1131
maxschlepzig

Respostas:

28

Peter me inspirou a escrever um script avançado (let), que pode até detectar pendrives (em vez de produzir coisas tolas como "ata0.00"). Ao contrário do script de Peter, você também receberá o sub-número (como em 4.01) se tiver mais de um dispositivo no mesmo controlador resp. canal. A saída será exatamente como você a obtém syslog. Testado. Trabalhando muito bem na minha caixa Debian, embora sempre haja muitas melhorias (por exemplo, regexps muito desajeitados). Mas segure! O número aparentemente alto de caracteres de escape que você pode encontrar nos meus regexps é apenas por motivos de compatibilidade! Você não pode assumir o GNU sedcom todos, e foi por isso que fiz isso sem regexps estendidos de propósito.

ATUALIZAÇÕES
(1) Não analisará mais a lssaída. (oops!) Como todos vocês sabem: não analise ls.
(2) Agora também funciona em ambientes somente leitura.
(3) Inspirado por uma sugestão deste bate-papo aqui , consegui novamente tornar as declarações sed muito menos complicadas.

#!/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"
erro de sintaxe
fonte
Apenas um lembrete de que o script pode não mostrar dispositivos com problemas. Eu tinha ata6 com erros no softreset falhou (1º FIS falhou) (Minor Issues) listou os dispositivos e ele não estava presente. se você souber que tem 4 discos no pc e apenas 3 aparecerem, talvez seja por isso.
Kendrick
11
@ Kendrick Bem, eu não culpo o script neste caso. Pois se você sabe como os drivers do kernel funcionam, isso ficará mais do que claro para você :) Sabe- se que os drivers do subsistema do kernel desistem quando os "problemas" são graves o suficiente. Isso indica que, para uma unidade compatível com UDMA, ela pode induzir várias redefinições de unidade e (eventualmente) tentar uma operação de unidade no modo PIO. No entanto, se isso for muito instável também (vários erros de tempo, etc.), o motorista dirá "vá embora" para a unidade. Para unidades PATA antigas, isso significa que uma reinicialização a frio será obrigatória para que a unidade seja exibida novamente.
Syntaxerror
Não é minha intenção significar culpa no script. apenas um lembrete do porquê pode estar faltando :) a placa controladora estúpida da flakey seagate fez com que fosse difícil descobrir o que estava acontecendo.
Kendrick
@ Kendrick Você está me dizendo cara. :) Bem, no meu livro, a Seagate nunca deveria ter comprado a Samsung. Adorei as últimas unidades (quando a Samsung ainda estava no negócio de armazenamento em massa), além de sua excelente equipe de suporte. Agora a Seagate assumiu tudo isso ... e ... uh-oh.
Syntaxerror 30/05
11

Veja /proc/scsi/scsi, que será algo parecido com isto:

$ 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 e ata1.00, scsi1 id 0 é sdb e ata2.00, etc.

Veja também /var/log/dmesg, que mostra as informações de carregamento do driver ata e tornará as coisas um pouco mais claras. Procure a linha que começa com "libata".

Phil Hollenback
fonte
8
Você também pode precisar usar 'lsscsi' - que fornece uma saída um pouco mais amigável para o ser humano - por exemplo, [0: 0: 0: 0] cd / dvd TSSTcorp CDDVDW SH-S202H SB00 / dev / sr0 [2: 0: 0: 0 ] disco ATA ST3500630AS 3.AA / dev / sda [3: 0: 0: 0] disco ATA WDC WD5000AAKS-0 01.0 / dev / sdb (neste servidor, executando um kernel 3.2.x, não há / proc / scsi *) (Desculpe, eu não consigo descobrir como obter qualquer formatação para o acima, para torná-lo legível)
David Goodwin
11
Esta deve ser uma resposta e não um comentário. Útil, rápido e fácil de ler de uma máquina e digitar em outra com problemas.
Elder Geek
10

Prefiro scripts em vez de explicações longas. Isso funciona na minha caixa do Ubuntu. Adicione comentários ao seu gosto:

# 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
Pedro
fonte
Seu script é um pouco menos assustador que a resposta, principalmente porque eu posso ver a coisa toda.
Isaaclw
11
Um pouco simplificando (funciona para mim no CentOS)ls -l /sys/block/sd* | sed -e 's@.*-> \.\..*/ata@/ata@' -e 's@/host@ @' -e 's@/target.*/@ @'
shirker
9

Isso é realmente bastante complicado. Embora seja seguro supor que "o scsi ID" é "o SATA ID menos um", prefiro estar realmente seguro e inspecionar o unique_idque assumo (com base nesta postagem ) é o identificador SATA.

Meu erro foi:

[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

Então, meu procedimento para descobrir o que ata4é:

  1. encontre o ID PCI do controlador SATA

    # lspci | grep -i sata
    00:1f.2 SATA controller: Intel Corporation 631xESB/632xESB SATA AHCI Controller (rev 09)
    
  2. encontre o ID exclusivo correspondente:

    # 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. por isso scsi_host/host3, podemos traduzir 3:x:x:x, para os quais podemos esperar para dmesgdescobrir mais:

    # 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. aqui está o nosso dispositivo, podemos (opcionalmente) encontrar o número de série para tirar esse dispositivo dali (ou verificar o cabeamento ou o que for) antes que nossa matriz RAID falhe totalmente:

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

E pronto!

anarcat
fonte
7

Tente o seguinte:

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

Eu nunca entendi o dmesg - algumas linhas são sobre "ata4", outras são sobre "scsi" ou sdc, mas ninguém atribui "ata4 ... sdc" o comando mostrado encontra o / sys / bus / path, onde ambos ata4 e sdc são especificados.

schweik
fonte
5

Eu tive o mesmo problema e consegui identificar unidades verificando dmesg. Lá você pode ver o identificador do controlador (termo correto ??) e o modelo do disco. Em seguida, use ls -l / dev / disk / by-id para combinar o número do modelo com / dev / sda (ou o que seja). Como alternativa, gosto do Disk Utility para essas informações. Nota: isso só funciona se seus discos tiverem números de modelo diferentes, caso contrário você não poderá distinguir entre os dois.

>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
ecellingsworth
fonte
2

A maneira mais fácil é revisar o log do kernel a partir da inicialização, uma vez que os nomes dos dispositivos da unidade são misturados em várias fontes (por exemplo, unidades USB) ou são atribuídos com base no tipo de dispositivo (por exemplo, cdrom pode ser scdX e tudo tem um sgX ) Na prática, a menos que você misture diferentes tipos de barramentos (por exemplo, SATA + USB), o dispositivo ata de menor número será sda, a menos que seja um dispositivo de cdrom.

Dependendo do seu sistema, ele pode ser adivinhado vagando pelo sysfs. No meu sistema, ls -l /sys/dev/blockrevela que 8:0(major: minor from / dev dev) aponta para o /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda mesmo modo, ls -l /sys/class/ata_portrevela os ata1pontos para os /sys/devices/pci0000:00/0000:00:1f.2/ata1/ata_port/ata1quais está no mesmo sub-dispositivo PCI.

Desde que eu uso SATA, e apenas uma unidade está em cada porta, posso deduzir que ata1.00 = sda. Todas as minhas unidades são .00, desconfio que se eu usasse um multiplicador de portas, minhas unidades receberiam .01, .02, .03 etc. e com base em seus logs, se você tiver ataX.01, o .01 deve ser mapeado para o "ID" na pasta host: channel: ID: LUN da /sys/dev/block/lista. Se você tiver múltiplos ataX/e hostY/pastas na mesma pasta do dispositivo PCI, então eu suspeito que a pasta aTAX numeradas menor corresponde ao menor pasta hosty numerada.

DerfK
fonte
2

Em /sys/class/ata_port/ata${n}/device/, você pode ver uma host${x}pasta. Por exemplo, na minha máquina:

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

O ${x}in host${x}refere-se ao primeiro número no [0:0:0:0]. Então, para mim, ata1refere-se ao host0que também pode ser representado no formato SCSI como 0:*:

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

O script abaixo fornece um bom resumo como este:

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

Assim, em uma linha por unidade, você tem o nome do dispositivo sdX , tamanho , modelo , s / n e os números pci e ata . O sdc acima corresponde a um leitor de cartão SD USB sem cartão inserido. Daí o ---- no lugar de informações reais.

#!/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

(testado apenas no ubuntu 12.04 / 14.04 e CentOS 6)

ndemou
fonte
Como isso equivale a mostrar o que é, por exemplo, o ATA 4.01?
Edward_178118
Na saída de exemplo, você vê sda: ... ata1 ... e sdb: ... ata3 .... E, de fato, sda estava em ata1 e sdb em ata2. Desde que escrevi e testei em 4 hosts diferentes, descobri o HW, onde o script acima não contém uma referência ao ata. Devo salientar que o dmesg | grep "ata [0-9]" nunca me falhou.
Ndemou
0

Um script para encontrar essas informações e muito mais pode ser encontrado em https://www.av8n.com/computer/disk-hw-host-bus-id

É semelhante ao script fornecido pelo Sr. Syntaxerror, mas mais sofisticado. - Ele funciona para unidades USB, bem como unidades ATA. - Ele fornece a marca, o modelo e o número de série da unidade, - e, é claro, o ponto de conexão. - É mais direto, legível e sustentável.

John Denker
fonte