Errori ATA Linux: stai traducendo in un nome di dispositivo?


36

Quando un box Linux riceve un errore ATA, lo registra in modo syslog con un messaggio che identifica il disco come "ata% d.00". Come posso tradurlo in un nome di dispositivo (ad es. /dev/sdb)? Sento che questo dovrebbe essere banale, ma non riesco a capirlo.


1
Vedi anche la mia risposta a una domanda simile su Unix-SE: unix.stackexchange.com/a/13988/1131
maxschlepzig

Risposte:


28

Peter mi ha ispirato a scrivere uno script avanzato (let), che può persino rilevare chiavi USB (invece di produrre cose stupide come "ata0.00"). Contrariamente allo script di Peter, otterrai anche il numero secondario (come in 4.01) se hai più di un dispositivo nello stesso controller o resp. canale. L'output sarà esattamente come lo ottieni syslog. Provato. Funziona molto bene sul mio Debian box, sebbene ci siano sempre molti miglioramenti (ad esempio regexps troppo goffi). Ma tienilo! Il numero apparentemente troppo alto di personaggi fuggiti che potresti trovare nei miei regexps è solo per motivi di compatibilità! Non puoi assumere GNU sedcon tutti, motivo per cui l'ho fatto senza regexps estesi di proposito.

AGGIORNAMENTI
(1) Non analizzerà più l' lsoutput. (oops!) Dato che lo sapete tutti: non analizzare ls.
(2) Ora funziona anche su ambienti di sola lettura.
(3) Ispirato da un suggerimento di questa chiacchierata qui sono riuscito a rendere le dichiarazioni sed molto meno complicate.

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

Solo un promemoria che lo script potrebbe non mostrare i dispositivi che presentano problemi. Ho avuto un errore ata6 con softreset fallito (1 ° FIS fallito) (problemi minori) elencato dvices e non era presente. se sai di avere 4 dischi nel PC e solo 3 appaiono, questo potrebbe essere il motivo.
Kendrick,

1
@Kendrick Bene, non darei la colpa alla sceneggiatura in questo caso. Perché se sai come funzionano i driver del kernel, questo ti sarà più che chiaro :) I driver del sottosistema del kernel sono noti a rinunciare quando i "problemi" sono abbastanza gravi. Questo indica che, per un'unità che supporta UDMA, può indurre reimpostazioni multiple dell'unità e (eventualmente) tentare un'operazione di unità in modalità PIO. Tuttavia, se anche questo risulta troppo instabile (vari errori di temporizzazione, ecc.), Il conducente dirà "vai via" all'unità. Per le vecchie unità PATA, ciò significa che un riavvio a freddo sarà obbligatorio affinché l'unità venga nuovamente visualizzata.
syntaxerror

Non è mia intenzione significare colpa della sceneggiatura. solo un promemoria sul motivo per cui potrebbe mancare :) la stupida scheda controller Seagate flakey ha reso difficile capire cosa stesse succedendo.
Kendrick,

@Kendrick Mi stai dicendo amico. :) Beh, nel mio libro Seagate non avrebbe mai dovuto acquistare Samsung. Mi sono piaciuti questi ultimi dischi (quando Samsung era ancora nel settore dell'archiviazione di massa), oltre al loro eccellente team di supporto. Ora Seagate ha assunto tutto questo ... e ... uh-oh.
syntaxerror,

11

Guarda /proc/scsi/scsi, che sarà simile a questo:

$ 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, ecc.

Guarda anche /var/log/dmesg, che mostra le informazioni di caricamento del driver ata e renderà le cose un po 'più chiare. Cerca la riga che inizia "libata".


8
Potrebbe anche essere necessario utilizzare 'lsscsi', che fornisce un output leggermente più amichevole per l'uomo, ad esempio [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 (su questo server, in esecuzione un kernel 3.2.x, non è presente / proc / scsi *) (Mi dispiace, non riesco a capire come ottenere alcuna formattazione in quanto sopra, per renderlo leggibile)
David Goodwin,

1
Questa dovrebbe essere una risposta piuttosto che un commento. Utile, veloce e facile da leggere da una macchina e scrivere su un'altra con problemi.
Anziano Geek,

10

Preferisco gli scriptlet anziché le spiegazioni lunghe. Funziona sulla mia scatola Ubuntu. Aggiungi commenti a tuo piacimento:

# 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

La tua sceneggiatura è un po 'meno spaventosa della risposta, soprattutto perché riesco a vedere tutto.
Isaaclw,

1
Un po 'di semplificazione (funziona per me su Centos)ls -l /sys/block/sd* | sed -e 's@.*-> \.\..*/ata@/ata@' -e 's@/host@ @' -e 's@/target.*/@ @'
Shirker

9

Questo è in realtà abbastanza complicato. Sebbene sia lecito ritenere che "l'ID scsi" sia "l'ID SATA meno uno", preferisco essere veramente sicuro e ispezionare il unique_idpresupposto che (in base a questo post ) sia l'identificatore SATA.

Il mio errore è stato:

[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

Quindi la mia procedura per scoprire cos'è ata4:

  1. trova l'ID PCI del controller SATA

    # lspci | grep -i sata
    00:1f.2 SATA controller: Intel Corporation 631xESB/632xESB SATA AHCI Controller (rev 09)
    
  2. trova l'ID univoco corrispondente:

    # 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. quindi è attivo scsi_host/host3, su cui possiamo tradurre 3:x:x:x, a cui possiamo fare richiesta dmesgper saperne di più:

    # 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. ecco il nostro dispositivo, possiamo (facoltativamente) trovare il numero di serie per estrarre quel dispositivo (o controllare il cablaggio o altro) prima che il nostro array RAID fallisca totalmente:

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

E hai finito!


7

Prova questo:

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

Non ho mai capito il dmesg - alcune righe riguardano "ata4" altre su "scsi" o sdc, ma nessuno assegna "ata4 ... sdc" il comando mostrato trova / sys / bus / path, dove sia ata4 che sdc sono specificati.


5

Ho avuto lo stesso problema ed è stato in grado di identificare le unità controllando dmesg. Lì puoi vedere l'identificatore del controller (termine corretto ??) e il modello del disco. Quindi utilizzare ls -l / dev / disk / by-id per far corrispondere il numero del modello a / dev / sda (o qualsiasi altra cosa). In alternativa, mi piace Disk Utility per queste informazioni. Nota: funziona solo se i dischi hanno numeri di modello diversi, altrimenti non è possibile distinguere tra i due.

>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

Il modo più semplice è rivedere il registro del kernel all'avvio, poiché i nomi dei dispositivi di unità sono mescolati da varie fonti (ad esempio unità USB) o sono assegnati in base al tipo di dispositivo (ovvero cdrom potrebbe essere scdX invece, e tutto ha uno sgX ). In pratica, a meno che tu non abbia mischiato diversi tipi di bus (es. SATA + USB) il dispositivo ata con il numero più basso sarà sda a meno che non sia un dispositivo cdrom.

A seconda del sistema, potrebbe essere divinato girovagando per sysfs. Sul mio sistema ls -l /sys/dev/blockrivela che 8:0(major: minor from / dev entry) punta allo /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda stesso modo, ls -l /sys/class/ata_portrivela quei ata1punti a /sys/devices/pci0000:00/0000:00:1f.2/ata1/ata_port/ata1cui si trova sullo stesso sotto-dispositivo PCI.

Poiché utilizzo SATA e su ciascuna porta è presente solo un'unità, posso dedurre che ata1.00 = sda. Tutte le mie unità sono .00, sospetto che se usassi un moltiplicatore di porte, le mie unità verrebbero fornite .01, .02, .03 ecc. Guardando i registri di altre persone i controller PATA usano .00 e .01 per master e slave e in base ai loro registri se hai ataX.01, il .01 dovrebbe essere mappato all '"ID" nell'host: canale: ID: cartella LUN /sys/dev/block/dall'elenco. Se hai più ataX/e hostY/cartelle nella stessa cartella del dispositivo PCI, sospetto che la cartella ataX con il numero più basso corrisponda alla cartella hostY con il numero più basso.


2

In /sys/class/ata_port/ata${n}/device/, puoi vedere una host${x}cartella. Ad esempio, sulla mia macchina:

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

In ${x}in si host${x}riferisce a quel primo numero in [0:0:0:0]. Quindi per me si ata1riferisce a ciò host0che può anche essere rappresentato in forma SCSI come 0:*:

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

0

Lo script seguente ti darà un bel riassunto come questo:

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

Quindi in una riga per unità hai nome, dimensioni , modello , s / n del dispositivo sdX e numeri pci e ata . Lo sdc sopra corrisponde a un lettore di schede SD USB senza scheda inserita. Da qui il ---- al posto delle informazioni reali.

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

(testato solo su Ubuntu 12.04 / 14.04 e CentOS 6)


In che modo questo ti mostra cosa è, ad esempio, ATA 4.01?
Edward_178118

Nell'output di esempio vedi sda: ... ata1 ... e sdb: ... ata3 .... E in effetti sda era in ata1 e sdb in ata2. Da quando l'ho scritto e testato su 4 host diversi ho scoperto HW dove lo script sopra non contiene un riferimento a ata. Dovrei sottolineare che dmesg | grep "ata [0-9]" non mi ha mai deluso.
ndemou,

0

Uno script per trovare queste informazioni e altro ancora è disponibile all'indirizzo https://www.av8n.com/computer/disk-hw-host-bus-id

È simile alla sceneggiatura fornita da Mr. Syntaxerror, ma più elaborata. - Funziona con unità USB e ATA. - Fornisce la marca e il modello dell'unità e il numero di serie, e ovviamente il punto di attacco. - È più semplice, leggibile e mantenibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.