ข้อผิดพลาด Linux ATA: กำลังแปลเป็นชื่ออุปกรณ์หรือไม่


36

เมื่อกล่องลีนุกซ์ได้รับข้อผิดพลาด ATA มันจะ syslogs พร้อมกับข้อความระบุดิสก์เป็น "ata% d.00" ฉันจะแปลสิ่งนั้นเป็นชื่ออุปกรณ์ได้อย่างไร (เช่น/dev/sdb) ฉันรู้สึกว่าสิ่งนี้จะเล็กน้อย แต่ฉันไม่สามารถคิดออก


1
ดูเพิ่มเติมคำตอบของฉันคำถามที่คล้ายกันบน Unix-SE: unix.stackexchange.com/a/13988/1131
maxschlepzig

คำตอบ:


28

ปีเตอร์เป็นแรงบันดาลใจให้ฉันเขียนสคริปต์ขั้นสูง (อนุญาต) ซึ่งสามารถตรวจจับแท่ง USB ได้ (แทนที่จะแสดงสิ่งที่โง่เช่น "ata0.00") ตรงกันข้ามกับสคริปต์ของปีเตอร์คุณจะได้รับหมายเลขย่อย (เช่นใน 4.01) หากคุณมีอุปกรณ์มากกว่าหนึ่งตัวในตัวควบคุมเดียวกัน ช่อง ผลลัพธ์จะตรงตามที่คุณได้รับsyslogมา ผ่านการทดสอบ ทำงานได้ดีบนกล่อง Debian ของฉันแม้ว่าจะมีการปรับปรุงอยู่เสมอ (เช่น regexps ที่เงอะงะเกินไป) แต่ถือไว้! จำนวนอักขระที่หนีออกมาที่ดูเหมือนจะสูงเกินไปที่คุณอาจพบใน regexps ของฉันนั้นเป็นเพราะเหตุผลด้านความเข้ากันได้! คุณไม่สามารถสันนิษฐาน GNU sedกับทุกคนได้ซึ่งเป็นสาเหตุที่ฉันทำโดยไม่ต้องใช้ regexps แบบขยาย

ปรับปรุง
(1) จะไม่มีอีกต่อไปแยกlsเอาท์พุท (อุ๊ปส์!) เนื่องจากคุณทุกคนรู้: อย่าแยก ls
(2) ตอนนี้ยังทำงานบนสภาพแวดล้อมแบบอ่านอย่างเดียว
(3) แรงบันดาลใจจากคำแนะนำจาก chit-chat ที่นี่ฉันมีการจัดการเพื่อรับงบ 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 กับชุด softres ล้มเหลว (1st FIS ล้มเหลว) (ปัญหาเล็กน้อย) ที่ระบุไว้ใน dvices และไม่มีอยู่ ถ้าคุณรู้ว่าคุณมี 4 ดิสก์ในพีซีและมีเพียง 3 รายการที่อาจเป็นสาเหตุ
Kendrick

1
@ Kenrick ดีฉันจะไม่ตำหนิสคริปต์ในกรณีนี้ สำหรับถ้าคุณรู้วิธีการทำงานของไดรเวอร์เคอร์เนลสิ่งนี้จะเป็นที่ชัดเจนยิ่งขึ้นสำหรับคุณ :) ไดรเวอร์ระบบย่อยเคอร์เนลเป็นที่รู้จักกันดีขึ้นเมื่อ "ปัญหา" รุนแรงพอ การอ่านนี้ว่าสำหรับไดรฟ์ที่มีคุณสมบัติ UDMA นั้นอาจทำให้เกิดการรีเซ็ตหลายไดรฟ์และ (ในที่สุด) พยายามดำเนินการไดรฟ์ในโหมด PIO อย่างไรก็ตามหากสิ่งนี้พิสูจน์ให้เห็นว่าไม่เสถียรเช่นกัน (ข้อผิดพลาดเกี่ยวกับช่วงเวลาต่าง ๆ เป็นต้น) ผู้ขับขี่จะพูดว่า "หายไป" กับไดรฟ์ สำหรับไดรฟ์ PATA แบบเก่าหมายความว่าการรีบูตระบบแบบเย็นจะบังคับให้ไดรฟ์ปรากฏขึ้นอีกครั้ง
ไวยากรณ์

ไม่ใช่ความตั้งใจของฉันที่จะหมายถึงการตำหนิสคริปต์ เพียงเตือนว่าทำไมมันอาจหายไป :) บอร์ดควบคุม seagate flakey flakey ทำให้มันเจ็บปวดที่จะคิดออกสิ่งที่เกิดขึ้น
Kendrick

@Kendrick คุณกำลังบอกฉันผู้ชาย :) ในหนังสือของฉัน Seagate ไม่ควรซื้อ Samsung ชอบไดรฟ์หลัง (เมื่อ Samsung ยังคงอยู่ในธุรกิจจัดเก็บข้อมูลขนาดใหญ่) พร้อมทีมสนับสนุนที่ยอดเยี่ยม ตอนนี้ Seagate ได้ครอบครองทั้งหมดนี้ ... และ ... uh-oh
ไวยากรณ์

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 ] disk 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
นี่ควรเป็นคำตอบมากกว่าความคิดเห็น มีประโยชน์รวดเร็วและง่ายต่อการอ่านจากเครื่องหนึ่งและพิมพ์บนเครื่องอื่นที่มีปัญหา
ผู้สูงอายุ Geek

10

ฉันชอบ scriptlets แทนที่จะเป็นคำอธิบายที่นิ่มนวล สิ่งนี้ใช้ได้กับกล่อง 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

1
ลดความซับซ้อนลงเล็กน้อย (ใช้ได้กับฉันใน Centos)ls -l /sys/block/sd* | sed -e 's@.*-> \.\..*/ata@/ata@' -e 's@/host@ @' -e 's@/target.*/@ @'
Shirker

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

ดังนั้นขั้นตอนของฉันเพื่อค้นหาata4คือ:

  1. ค้นหา PCI id ของคอนโทรลเลอร์ SATA

    # 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. ดังนั้นจึงเป็นเรื่อง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 / บัส / เส้นทางที่ทั้ง ata4 และ sdc ระบุไว้


5

ฉันมีปัญหาเดียวกันและสามารถระบุไดรฟ์โดยการตรวจสอบ dmesg ที่นั่นคุณสามารถดูตัวระบุคอนโทรลเลอร์ (คำที่ถูกต้อง ??) และรุ่นของดิสก์ได้ จากนั้นใช้ ls -l / dev / disk / by-id เพื่อจับคู่หมายเลขรุ่นกับ / dev / sda (หรืออะไรก็ตาม) หรือฉันชอบ Disk Utility สำหรับข้อมูลนี้ หมายเหตุ: ใช้งานได้เฉพาะหากดิสก์ของคุณมีหมายเลขรุ่นที่แตกต่างกันมิฉะนั้นคุณจะไม่สามารถแยกความแตกต่างระหว่างทั้งสองได้

>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) ชี้ไปที่/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" ในโฮสต์: ช่อง: ID: โฟลเดอร์ LUN จาก/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ชื่ออุปกรณ์, ขนาด , รูปแบบ , s / nและPCIและATAหมายเลข sdc ด้านบนตรงกับเครื่องอ่านการ์ด SD USB โดยไม่ต้องใส่การ์ด ดังนั้น ---- แทนข้อมูลจริง

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

ในตัวอย่างผลลัพธ์ที่คุณเห็น sda: ... ata1 ... และ sdb: ... ata3 .... และแน่นอน sda อยู่ที่ ata1 และ sdb ที่ ata2 ตั้งแต่ฉันเขียนและทดสอบกับโฮสต์ 4 แห่งฉันพบว่า HW ที่สคริปต์ข้างต้นไม่มีการอ้างอิงถึง ata ฉันควรชี้ให้เห็นว่า dmesg | grep "ata [0-9]" ไม่เคยทำให้ฉันผิดหวัง
ndemou

0

สคริปต์เพื่อค้นหาข้อมูลนี้และอีกมากมายสามารถดูได้ที่ https://www.av8n.com/computer/disk-hw-host-bus-id

มันคล้ายกับสคริปต์ที่ได้รับจาก Mr. Syntaxerror แต่เป็นนักเล่นที่ดีกว่า - ใช้งานได้กับไดรฟ์ USB และไดรฟ์ ATA - มีการจัดทำไดรฟ์และรุ่นและหมายเลขซีเรียล - และแน่นอนจุดเชื่อมต่อ - ตรงไปตรงมาอ่านและบำรุงรักษาได้มากกว่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.