Direkt zum Hauptinhalt

HDD Tray ermitteln LED blinken und/oder austauschen

Beschreibung:

Es gibt ein tolles Tool. Mit der man die LED zum Tray blinken lassen kann.
Noch ein kleines Script dazu wo man nur dass device angeben muss.Ein weiteres script zum Datenträger tausch.
Lässt slot blinken.
festplatte tauschen
Alte festplatte wird deregistriert und neue hinzugefügt.
LED ausgeschaltet.
BAM

Durchführung:

apt-get install -y lsscsi sg3-utils

Festplatten anzeigen lassen:

lsscsi -g

Ausgabe:

[1:0:0:0]    cd/dvd  Slimtype DVD A  DS8ACSH   LP5M  /dev/sr0   /dev/sg17
[3:0:0:0]    disk    SEAGATE  XS400ME70004     0004  /dev/sda   /dev/sg0 
[3:0:1:0]    disk    SEAGATE  ST20000NM002D    E004  /dev/sdb   /dev/sg1 
[3:0:2:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdc   /dev/sg2 
[3:0:3:0]    disk    SEAGATE  ST20000NM002D    E006  /dev/sdd   /dev/sg3 
[3:0:4:0]    disk    WDC      WUS721010AL5204  C980  /dev/sde   /dev/sg4 
[3:0:5:0]    disk    SEAGATE  ST20000NM002D    E006  /dev/sdf   /dev/sg5 
[3:0:6:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdg   /dev/sg6 
[3:0:7:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdh   /dev/sg7 
[3:0:8:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdi   /dev/sg8 
[3:0:9:0]    disk    WDC      WUS721010AL5204  C980  /dev/sdj   /dev/sg9 
[3:0:10:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdk   /dev/sg10
[3:0:11:0]   disk    SEAGATE  XS400ME70004     0004  /dev/sdl   /dev/sg11
[3:0:12:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdm   /dev/sg12
[3:0:13:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdn   /dev/sg13
[3:0:14:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdo   /dev/sg14
[3:0:15:0]   disk    WDC      WUS721010AL5204  C980  /dev/sdp   /dev/sg15
[3:0:16:0]   enclosu BROADCOM VirtualSES       03    -          /dev/sg16
[4:0:0:0]    cd/dvd  AMI      Virtual CDROM0   1.00  /dev/sr1   /dev/sg18

Script:

nano /usr/local/bin/identify-disk.sh

Inhalt

#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
Usage:
  identify-disk [--on|--off|--blink SECONDS] [--symlink|--ses] /dev/sdX|sdX|sdXn

Optionen:
  --on / --off / --blink SECONDS   LED steuern
  --symlink                        nur sysfs/enclosure_device* nutzen
  --ses                            nur SES (sg_ses) nutzen
  (ohne Methode)                   auto: erst symlink, dann SES-Fallback

Beispiele:
  identify-disk --on        sdi
  identify-disk --blink 10  sdg8
  identify-disk --off       --symlink sdi
  identify-disk --on        --ses     sdi
USAGE
}

MODE="on"
BLINK_SECS=0
METHOD="auto"   # auto | symlink | ses

[[ $# -lt 1 ]] && { usage; exit 1; }

while [[ $# -gt 0 ]]; do
  case "${1:-}" in
    --on) MODE="on"; shift ;;
    --off) MODE="off"; shift ;;
    --blink) MODE="blink"; BLINK_SECS="${2:-}"; [[ -z "$BLINK_SECS" ]] && { echo "Fehlende Sekunden bei --blink"; exit 1; }; shift 2 ;;
    --symlink) METHOD="symlink"; shift ;;
    --ses) METHOD="ses"; shift ;;
    -h|--help) usage; exit 0 ;;
    *) DISK="$1"; shift ;;
  esac
done

# --- Device normalisieren (Partitionen abschneiden, /dev/ hinzufügen) ---
[[ "$DISK" =~ ^sd ]] && DISK="/dev/$DISK"
BASE="$(basename "$DISK")"
BASE_NOPART="${BASE%%[0-9]*}"
DISK="/dev/$BASE_NOPART"
[[ -b "$DISK" ]] || { echo "Gerät nicht gefunden: $DISK"; exit 1; }

do_symlink() {
  local p="/sys/class/block/${BASE_NOPART}/device"
  local enc=( "$p"/enclosure_device* )
  [[ -e "${enc[0]}" ]] || { echo "Kein enclosure_device* für $DISK gefunden."; return 2; }
  local LOCATE="${enc[0]}/locate"
  [[ -w "$LOCATE" ]] || { echo "'locate' nicht verfügbar/schreibbar unter ${enc[0]}."; return 3; }
  local SLOT_FILE="${enc[0]}/slot"
  local slot="$(cat "$SLOT_FILE" 2>/dev/null || echo "?")"
  case "$MODE" in
    on)    echo 1 | sudo tee "$LOCATE" >/dev/null; echo "Identify-LED an (Slot $slot via sysfs locate) – $DISK";;
    off)   echo 0 | sudo tee "$LOCATE" >/dev/null; echo "Identify-LED aus (Slot $slot via sysfs locate) – $DISK";;
    blink) echo 1 | sudo tee "$LOCATE" >/dev/null; echo "Identify-LED an (Slot $slot) – blinke $BLINK_SECS s…"; sleep "$BLINK_SECS"; echo 0 | sudo tee "$LOCATE" >/dev/null; echo "Identify-LED wieder aus.";;
  esac
}

do_ses() {
  command -v lsscsi >/dev/null 2>&1 || { echo "lsscsi fehlt (apt install lsscsi)"; return 4; }
  command -v sg_ses  >/dev/null 2>&1 || { echo "sg3-utils (sg_ses) fehlt (apt install sg3-utils)"; return 5; }

  local LINE
  LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
  [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; return 6; }

  if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
    local HOST="${BASH_REMATCH[1]}" BUS="${BASH_REMATCH[2]}" TARGET="${BASH_REMATCH[3]}" LUN="${BASH_REMATCH[4]}"
  else
    echo "Konnte SCSI-Adresse nicht parsen."; return 7
  fi

  local SES_LINE SES_DEV
  SES_LINE="$(lsscsi -g | awk -v h="$HOST" -v b="$BUS" '$2=="enclosu" && $1 ~ ("\\["h":"b":"){print; exit}')"
  [[ -n "$SES_LINE" ]] || { echo "Kein SES/Enclosure auf ${HOST}:${BUS} gefunden (HW-RAID? Hersteller-CLI nötig)."; return 8; }
  SES_DEV="$(echo "$SES_LINE" | awk '{print $NF}')"
  [[ -e "$SES_DEV" ]] || { echo "SES-Gerät existiert nicht: $SES_DEV"; return 9; }

  local SAS_PATH="/sys/class/scsi_device/${HOST}:${BUS}:${TARGET}:${LUN}/device/sas_address"
  if [[ ! -r "$SAS_PATH" ]]; then
    echo "Konnte SAS-Adresse nicht aus $SAS_PATH lesen."; return 10
  fi
  local DISK_SAS; DISK_SAS="$(tr -d '\n' < "$SAS_PATH")"
  [[ -n "$DISK_SAS" ]] || { echo "Leere SAS-Adresse gelesen."; return 11; }

  # passender SES-Index über sg_ses -p aes via SAS address
  local INDEX
  INDEX="$(sg_ses -p aes "$SES_DEV" 2>/dev/null \
    | awk -v want="$DISK_SAS" '
        /Element index:/ {idx=$3; gsub(":","",idx)}
        /SAS address:/ && $3 ~ /^0x/ {sas=$3; if (tolower(sas)==tolower(want)) {print idx; exit}}
      ')"

  # Fallback über physische Slotnummer, falls SAS-Match nicht gefunden wurde
  if [[ -z "$INDEX" ]]; then
    local p="/sys/class/block/${BASE_NOPART}/device"
    local enc=( "$p"/enclosure_device* )
    if [[ -e "${enc[0]}" && -r "${enc[0]}/slot" ]]; then
      local PHY_SLOT; PHY_SLOT="$(cat "${enc[0]}/slot" 2>/dev/null || true)"
      if [[ -n "$PHY_SLOT" ]]; then
        INDEX="$(sg_ses -p aes "$SES_DEV" 2>/dev/null \
          | awk -v slot="$PHY_SLOT" '
              /Element index:/ {idx=$3; gsub(":","",idx)}
              /device slot number:/ {if ($5==slot) {print idx; exit}}
            ')"
      fi
    fi
  fi

  [[ -n "$INDEX" ]] || { echo "Konnte passenden SES-Index nicht ermitteln (SAS/slot-Mapping fehlgeschlagen)."; return 12; }

  case "$MODE" in
    on)    sg_ses --index="$INDEX" --set=ident "$SES_DEV"; echo "Identify-LED an: SES index $INDEX (Disk $DISK) via $SES_DEV";;
    off)   sg_ses --index="$INDEX" --clear=ident "$SES_DEV"; echo "Identify-LED aus: SES index $INDEX (Disk $DISK) via $SES_DEV";;
    blink) sg_ses --index="$INDEX" --set=ident "$SES_DEV"; echo "LED an für $BLINK_SECS s: SES index $INDEX (Disk $DISK)"; sleep "$BLINK_SECS"; sg_ses --index="$INDEX" --clear=ident "$SES_DEV"; echo "LED aus.";;
  esac
}

case "$METHOD" in
  symlink)
    do_symlink || exit $?
    ;;
  ses)
    do_ses || exit $?
    ;;
  auto)
    if do_symlink; then
      exit 0
    else
      echo "(Auto) Fallback auf SES…"
      do_ses
    fi
    ;;
  *)
    echo "Unbekannte Methode: $METHOD"; usage; exit 1 ;;
esac

Ausführbar machen

chmod +x /usr/local/bin/identify-disk.sh

Hilfe/Bedienung

sage:
  identify-disk [--on|--off|--blink SECONDS] [--symlink|--ses] /dev/sdX|sdX|sdXn

Optionen:
  --on / --off / --blink SECONDS   LED steuern
  --symlink                        nur sysfs/enclosure_device* nutzen
  --ses                            nur SES (sg_ses) nutzen
  (ohne Methode)                   auto: erst symlink, dann SES-Fallback

Beispiele:
  identify-disk --on        sdi
  identify-disk --blink 10  sdg8
  identify-disk --off       --symlink sdi
  identify-disk --on        --ses     sdi

Alte Laufwerke entfernen:

Sobald alte Laufwerke entfernt werden, bleiben Sie tot in der Liste.
Erst Laufwerk entfernen. Dann neu einschieben.
Das machen wir wieder mit einem script. Das Script wartet solange bis wir die festplatte getauscht haben.
wenn getauscht bestätigen.

nano /usr/local/bin/scsi-hotswap.sh

Inhalt

#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
Usage:
  scsi-hotswap [--method auto|symlink|ses] [--blink N|--no-led] [--no-prompt] /dev/sdX|sdX|sdXn

Optionen:
  --method M     M = auto (default) | symlink | ses
  --blink N      LED vor dem Tausch N Sekunden blinken (statt dauerhaft an)
  --no-led       keine LED-Steuerung
  --no-prompt    nicht auf ENTER warten (setze voraus, dass neue Platte schon steckt)

Beispiele:
  scsi-hotswap sdi
  scsi-hotswap --method symlink --blink 8 sdg8
  scsi-hotswap --method ses --no-prompt sdm
USAGE
}

METHOD="auto"      # auto | symlink | ses
BLINK_SECS=0       # 0 = steady on
USE_LED=1
PROMPT=1

[[ $# -lt 1 ]] && { usage; exit 1; }
while [[ $# -gt 0 ]]; do
  case "${1:-}" in
    --method) METHOD="${2:-}"; shift 2 ;;
    --blink)  BLINK_SECS="${2:-}"; [[ -z "$BLINK_SECS" ]] && { echo "Fehlende Sekunden bei --blink"; exit 1; }; shift 2 ;;
    --no-led) USE_LED=0; shift ;;
    --no-prompt) PROMPT=0; shift ;;
    -h|--help) usage; exit 0 ;;
    *) DISK="$1"; shift ;;
  esac
done

# --- Device normalisieren ---
[[ "$DISK" =~ ^sd ]] && DISK="/dev/$DISK"
BASE="$(basename "$DISK")"
BASE_NOPART="${BASE%%[0-9]*}"
DISK="/dev/$BASE_NOPART"
[[ -b "$DISK" ]] || { echo "Gerät nicht gefunden: $DISK"; exit 1; }

need() { command -v "$1" >/dev/null 2>&1 || { echo "$1 fehlt. Bitte installieren."; exit 1; }; }

# --------------------------
# LED via sysfs (symlink-Weg)
# --------------------------
# merkt sich LOCATE_PATH_CACHED+SLOT_CACHED, damit "off" nach dem Swap immer klappt
LOCATE_PATH_CACHED=""
SLOT_CACHED=""

led_symlink() {
  local mode="$1"  # on|off|blink
  local LOCATE_PATH=""
  local SLOT=""

  # bereits gecachten Pfad benutzen, wenn vorhanden
  if [[ -n "$LOCATE_PATH_CACHED" && -e "$LOCATE_PATH_CACHED" ]]; then
    LOCATE_PATH="$LOCATE_PATH_CACHED"
    SLOT="$SLOT_CACHED"
  else
    local p="/sys/class/block/${BASE_NOPART}/device"
    local enc=( "$p"/enclosure_device* )
    [[ -e "${enc[0]}" ]] || return 2
    LOCATE_PATH="${enc[0]}/locate"
    [[ -w "$LOCATE_PATH" ]] || return 3
    SLOT="$(cat "${enc[0]}/slot" 2>/dev/null || echo "?")"
    LOCATE_PATH_CACHED="$LOCATE_PATH"
    SLOT_CACHED="$SLOT"
  fi

  local slot_label=""
  [[ -n "$SLOT" ]] && slot_label=" (Slot $SLOT)"

  case "$mode" in
    on)
      echo 1 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED an (Slot $SLOTan${slot_label} via sysfs)sysfs – $DISK"
      ;;
    off)
      echo 0 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED aus (Slot $SLOTaus${slot_label} via sysfs)sysfs – $DISK"
      ;;
    blink)
      echo 1 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED an (Slot $SLOT)an${slot_label} – blinke ${BLINK_SECS}s…"
      sleep "$BLINK_SECS"
      echo 0 | sudo tee "$LOCATE_PATH" >/dev/null
      echo "LED aus."
      ;;
  esac
  return 0
}

# -------------------------------------------
# SES-Index + Slotnummer + SES-Device ermitteln (per SAS)
# -------------------------------------------
get_ses_index() {
  # Outputs (echo): "<SES_DEV> <INDEX> <SLOTNUM> <HOST> <BUS> <TARGET> <LUN>"
  need lsscsi; need sg_ses

  local LINE
  LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
  [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden." >&2; return 1; }

  if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
    local HOST="${BASH_REMATCH[1]}" BUS="${BASH_REMATCH[2]}" TARGET="${BASH_REMATCH[3]}" LUN="${BASH_REMATCH[4]}"
  else
    echo "Konnte SCSI-Adresse nicht parsen." >&2; return 1
  fi

  local SES_LINE SES_DEV
  SES_LINE="$(lsscsi -g | awk -v h="$HOST" -v b="$BUS" '$2=="enclosu" && $1 ~ ("\\["h":"b":"){print; exit}')"
  [[ -n "$SES_LINE" ]] || { echo "Kein SES/Enclosure auf ${HOST}:${BUS} gefunden (HW-RAID?)." >&2; return 1; }
  SES_DEV="$(echo "$SES_LINE" | awk '{print $NF}')"
  [[ -e "$SES_DEV" ]] || { echo "SES-Gerät existiert nicht: $SES_DEV" >&2; return 1; }

  local SAS_PATH="/sys/class/scsi_device/${HOST}:${BUS}:${TARGET}:${LUN}/device/sas_address"
  [[ -r "$SAS_PATH" ]] || { echo "SAS-Adresse nicht lesbar: $SAS_PATH" >&2; return 1; }
  local DISK_SAS; DISK_SAS="$(tr -d '\n' < "$SAS_PATH")"
  [[ -n "$DISK_SAS" ]] || { echo "Leere SAS-Adresse." >&2; return 1; }

  # In einem Durchlauf: Index + physische Slotnummer zu *dieser* Disk finden
  local INDEX INDEX="$SLOTNUM
  read INDEX SLOTNUM < <(sg_ses -p aes "$SES_DEV" 2>/dev/null \
    | awk -v want="$DISK_SAS" '
        /Element index:/              {idx=$3; gsub(":","",idx); slot=""}
        /device slot number:/         {slot=$5}
        /SAS address:/ && $3 ~ /^0x/  {sas=$3; if (tolower(sas)==tolower(want)) {print idx;idx, slot; exit}}
      ')"

  # Fallback viaüber physischemphysische SlotSlotnummer aus sysfs (falls sysfs-slot verfügbar)vorhanden)
  if [[ -z "$INDEX"{INDEX:-}" || -z "${SLOTNUM:-}" ]]; then
    local p="/sys/class/block/${BASE_NOPART}/device"
    local enc=( "$p"/enclosure_device* )
    if [[ -e "${enc[0]}" && -r "${enc[0]}/slot" ]]; then
      local PHY_SLOT; PHY_SLOT="$(cat "${enc[0]}/slot" 2>/dev/null || true)"
      if [[ -n "$PHY_SLOT" ]]; then
        SLOTNUM="$PHY_SLOT"
        INDEX="$(sg_ses -p aes "$SES_DEV" 2>/dev/null \
          | awk -v slot="$PHY_SLOT" '
              /Element index:/ {idx=$3; gsub(":", "", idx)}
              /device slot number:/ {if ($5==slot) {print idx; exit}}
            ')"
      fi
    fi
  fi

  # Es kann vorkommen, dass SLOTNUM leer bleibt → ist ok; dann nur Index nutzen
  [[ -n "$INDEX" ]] || { echo "SES-Index konnte nicht ermittelt werden." >&2; return 1; }
  echo "$SES_DEVSES_DEV" "$INDEXINDEX" "$HOST{SLOTNUM:-}" "$BUSHOST" "$TARGETBUS" "$TARGET" "$LUN"
}

# -----------------------
# LED via SES (sg_ses)
# -----------------------
led_ses() {
  local mode="$1" SES_DEV="$2" INDEX="$3" SLOTNUM="${4:-}"
  need sg_ses
  local slot_label=""
  [[ -n "$SLOTNUM" ]] && slot_label=" (Slot $SLOTNUM)"
  case "$mode" in
    on)
      sg_ses --index="$INDEX" --set=ident "$SES_DEV"
      echo "LED anan${slot_label}, (SES index $INDEX via $SES_DEV)SES_DEV – $DISK"
      ;;
    off)
      sg_ses --index="$INDEX" --clear=ident "$SES_DEV"
      echo "LED ausaus${slot_label}, (SES index $INDEX via $SES_DEV)SES_DEV – $DISK"
      ;;
    blink)
      sg_ses --index="$INDEX" --set=ident "$SES_DEV"
      echo "LED anan${slot_label} – blinke ${BLINK_SECS}s (SES index $INDEX)…"
      sleep "$BLINK_SECS"
      sg_ses --index="$INDEX" --clear=ident "$SES_DEV"
      echo "LED aus."
      ;;
  esac
}

# ---------------------------------------------
# Methode wählen & LED einschalten (falls gew.)
# ---------------------------------------------
SES_DEV=""; INDEX=""; SLOTNUM=""; HOST=""; BUS=""; TARGET=""; LUN=""
OLDDEV=""

if (( USE_LED )); then
  case "$METHOD" in
    symlink)
      led_symlink "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)" \
        || { echo "Symlink-LED nicht verfügbar."; exit 1; }
      # H:B:T:L brauchen& wir trotzdem gleichOLDDEVrsr delete/scan:
      need lsscsi
      LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
      [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; exit 1; }
      OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")"
      if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
        HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
      else
        echo "Konnte SCSI-Adresse nicht parsen."; exit 1
      fi
      ;;
    ses)
      read SES_DEV INDEX SLOTNUM HOST BUS TARGET LUN < <(get_ses_index) || exit 1
      led_ses "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)" "$SES_DEV" "$INDEX" "$SLOTNUM"
      # OLDDEV zusätzlich erfassen (nur Info)
      need lsscsi
      LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
      [[ -n "$LINE" ]] && OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")" || true
      ;;
    auto)
      if ! led_symlink "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)"; then
        echo "(Auto) Fallback auf SES…"
        read SES_DEV INDEX SLOTNUM HOST BUS TARGET LUN < <(get_ses_index) || exit 1
        led_ses "$([[ $BLINK_SECS -gt 0 ]] && echo blink || echo on)" "$SES_DEV" "$INDEX" "$SLOTNUM"
      else
        # Symlink-Weg erfolgreich: H:B:T:L & OLDDEV besorgen
        need lsscsi
        LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
        [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; exit 1; }
        OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")"
        if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
          HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
        else
          echo "Konnte SCSI-Adresse nicht parsen."; exit 1
        fi
      fi
      ;;
    *) echo "Unbekannte Methode: $METHOD"; exit 1 ;;
  esac
else
  # Keine LED: wir brauchen nur H:B:T:L & OLDDEV
  need lsscsi
  LINE="$(lsscsi -g | awk -v d="$DISK" '{if ($(NF-1)==d) {print; exit}}')"
  [[ -n "$LINE" ]] || { echo "Konnte $DISK nicht in 'lsscsi -g' finden."; exit 1; }
  OLDDEV="$(awk '{print $(NF-1)}' <<<"$LINE")"
  if [[ "$LINE" =~ \[([0-9]+):([0-9]+):([0-9]+):([0-9]+)\] ]]; then
    HOST="${BASH_REMATCH[1]}"; BUS="${BASH_REMATCH[2]}"; TARGET="${BASH_REMATCH[3]}"; LUN="${BASH_REMATCH[4]}"
  else
    echo "Konnte SCSI-Adresse nicht parsen."; exit 1
  fi
fi

# -------------
# Deregister
# -------------
echo ">>> Entferne $DISK (SCSI ${HOST}:${BUS}:${TARGET}:${LUN})"
echo 1 | sudo tee "/sys/class/scsi_device/${HOST}:${BUS}:${TARGET}:${LUN}/device/delete" >/dev/null || true

# -------------
# Prompt / Swap (ohne Slotnummer)
# -------------
if (( PROMPT )); then
  read -p ">>> Bitte neue Festplatte in Slot ${TARGET} einsetzen und ENTER drücken… " _
fi

# -------------
# Rescan (gezielt für den Target-Slot)
# -------------
echo ">>> Rescanne Slot (Target ${TARGET}) über host${HOST}…"
echo "${HOST} ${BUS} ${TARGET}" | sudo tee "/sys/class/scsi_host/host${HOST}/scan" >/dev/null

# -------------
# Neues Device finden (by H:B:T:L)
# -------------
echo ">>> Warte auf neues Blockdevice im Slot (Target ${TARGET})…"
need lsscsi
NEWDISK=""
for i in {1..20}; do
  NEWLINE="$(lsscsi -g | awk -v h="$HOST" -v b="$BUS" -v t="$TARGET" '$1==sprintf("[%d:%d:%d:0]",h,b,t){print; exit}')"
  if [[ -n "$NEWLINE" ]]; then
    NEWDISK="$(awk '{print $(NF-1)}' <<<"$NEWLINE")"
    echo ">>> Neues Device: $NEWDISK  ($NEWLINE)"
    break
  fi
  sleep 1
done
if [[ -n "$NEWDISK" ]]; ||then
  if [[ -n "$OLDDEV" ]]; then
    if [[ "$NEWDISK" == "$OLDDEV" ]]; then
      echo ">>> Hinweis: Laufwerksbuchstabe unverändert geblieben ($NEWDISK) – alles ok."
    else
      echo ">>> Hinweis: Buchstabe wechselte: alt=$OLDDEV neu=$NEWDISK (normal bei Hot-Swap)."
    fi
  fi
else
  echo "Hinweis: KeinIm Zeitfenster kein neues Device innerhalbsichtbar. desEntweder Zeitfensters gesehen (ggf. Treiber/Controller langsamlangsam, /oder prüfen).der Slot wurde noch nicht neu gemeldet. Prüfe lsscsi/Logs."
fi

# -------------
# LED aus
# -------------
if (( USE_LED )); then
  case "$METHOD" in
    symlink)
      led_symlink off || true           # nutzt den gecachten locate-Pfad
      ;;
    ses)
      led_ses off "$SES_DEV" "$INDEX" "$SLOTNUM" || true
      ;;
    auto)
      if [[ -n "${SES_DEV:-}" && -n "${INDEX:-}" ]]; then
        led_ses off "$SES_DEV" "$INDEX" "$SLOTNUM" || true
      else
        led_symlink off || true
      fi
      ;;
  esac
fi

echo ">>> Fertig."

Nun noch ausführbar machen

chmod +x /usr/local/bin/scsi-hotswap.sh

Hilfe/Benutzung:

Usage:
  scsi-hotswap [--method auto|symlink|ses] [--blink N|--no-led] [--no-prompt] /dev/sdX|sdX|sdXn

Optionen:
  --method M     M = auto (default) | symlink | ses
  --blink N      LED vor dem Tausch N Sekunden blinken (statt dauerhaft an)
  --no-led       keine LED-Steuerung
  --no-prompt    nicht auf ENTER warten (setze voraus, dass neue Platte schon steckt)

Beispiele:
  scsi-hotswap sdi
  scsi-hotswap --method symlink --blink 8 sdg8
  scsi-hotswap --method ses --no-prompt sdm

Ausgabe:

root@backupsrv001:~# scsi-hotswap.sh /dev/sdq
>>> Entferne /dev/sdq (SCSI 3:0:17:0)
>>> Bitte neue Festplatte in Slot 17 einsetzen...
Weiter mit ENTER, wenn neue Platte steckt.
>>> Rescanne Slot 17...
>>> Neue Device-Liste: