Skip to content

ORA-15063 ASM Discovered Insufficient Number of Disks - Disk Discovery Fix

ORA-15063: ASM Discovered an Insufficient Number of Disks for Diskgroup

Section titled “ORA-15063: ASM Discovered an Insufficient Number of Disks for Diskgroup”

Error Text: ORA-15063: ASM discovered an insufficient number of disks for diskgroup "diskgroup_name"

This error occurs when ASM (Automatic Storage Management) cannot discover enough disks to create or mount a diskgroup according to its redundancy requirements. The error typically appears during diskgroup creation, mount operations, or after system changes that affect disk visibility.

Redundancy Requirements
├── EXTERNAL REDUNDANCY
│ ├── Minimum: 1 disk
│ ├── No ASM mirroring
│ └── Relies on external protection
├── NORMAL REDUNDANCY
│ ├── Minimum: 2 disks (2 failure groups)
│ ├── Recommended: 3+ disks
│ └── 2-way mirroring
└── HIGH REDUNDANCY
├── Minimum: 3 disks (3 failure groups)
├── Recommended: 5+ disks
└── 3-way mirroring
-- ASM discovers disks based on:
-- 1. ASM_DISKSTRING parameter paths
-- 2. Disk header validation
-- 3. Permissions and accessibility
-- 4. Disk state (CANDIDATE, MEMBER, etc.)
  • Incorrect ASM_DISKSTRING parameter
  • Disk paths not included in discovery string
  • Wildcard patterns not matching disks
  • Case sensitivity in path names
Terminal window
# Permission issues
# Ownership problems
# SELinux blocking access
# Disk not visible to ASM instance
  • Disks not properly provisioned
  • Multipath configuration incomplete
  • Storage array mapping issues
  • SAN zoning problems
  • Device drivers not loaded
  • UDEV rules misconfigured
  • Disk devices not created
  • Kernel module problems
-- Connect to ASM instance
sqlplus / as sysasm
-- Check current discovery string
SHOW PARAMETER asm_diskstring;
-- List all discovered disks
SELECT path, header_status, state, total_mb
FROM v$asm_disk
ORDER BY path;
-- Count available disks by status
SELECT header_status, COUNT(*) as disk_count
FROM v$asm_disk
GROUP BY header_status
ORDER BY header_status;
Terminal window
# List block devices
lsblk
ls -la /dev/sd*
ls -la /dev/mapper/*
# Check Oracle ASM disks
oracleasm listdisks
ls -la /dev/oracleasm/disks/
# Check multipath devices
multipath -ll
# Verify disk accessibility
for disk in /dev/oracleasm/disks/*; do
echo "Checking $disk"
dd if=$disk of=/dev/null bs=1M count=1 2>&1 | grep -v records
done
Terminal window
# Check disk headers for ASM membership
for disk in /dev/oracleasm/disks/*; do
echo "=== Disk: $disk ==="
kfed read $disk | grep -E "grptyp|dskname|grpname|provstr"
done
# Check specific disk
kfed read /dev/oracleasm/disks/DISK1 | head -50
Terminal window
# Check loaded kernel modules
lsmod | grep oracle
# Check UDEV rules
cat /etc/udev/rules.d/*asm*.rules
# Check SELinux status
getenforce
ls -Z /dev/oracleasm/disks/
# Check disk permissions
ls -la /dev/oracleasm/disks/
-- Add all possible disk locations
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/*','/dev/sd*','/dev/mapper/*' SCOPE=BOTH;
-- For specific paths
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/DISK*' SCOPE=BOTH;
-- Force re-discovery
ALTER SYSTEM SET asm_diskstring = '' SCOPE=MEMORY;
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/*' SCOPE=MEMORY;
-- Verify discovery
SELECT path, header_status FROM v$asm_disk ORDER BY path;
-- Test specific pattern
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/DATA*' SCOPE=MEMORY;
SELECT COUNT(*) FROM v$asm_disk WHERE header_status = 'CANDIDATE';
-- Test multiple patterns
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/*','/dev/raw/*' SCOPE=MEMORY;
SELECT path, header_status FROM v$asm_disk WHERE header_status IN ('CANDIDATE', 'MEMBER');
Terminal window
# Create ASM disk from partition
oracleasm createdisk DISK1 /dev/sdb1
oracleasm createdisk DISK2 /dev/sdc1
oracleasm createdisk DISK3 /dev/sdd1
# Scan for new disks
oracleasm scandisks
oracleasm listdisks
# Verify disk creation
ls -la /dev/oracleasm/disks/
Terminal window
# Check multipath configuration
cat /etc/multipath.conf
# Add ASM devices to multipath
multipath -a /dev/sdb
multipath -a /dev/sdc
# Reload multipath
multipath -r
multipath -ll
# Create ASM disks on multipath devices
oracleasm createdisk DISK1 /dev/mapper/mpatha
Terminal window
# Oracle ASM disks
chown grid:asmadmin /dev/oracleasm/disks/*
chmod 660 /dev/oracleasm/disks/*
# Raw devices
chown grid:asmadmin /dev/sd[b-z]*
chmod 660 /dev/sd[b-z]*
# Multipath devices
chown grid:asmadmin /dev/mapper/asm*
chmod 660 /dev/mapper/asm*
Terminal window
# Create UDEV rule for ASM disks
cat > /etc/udev/rules.d/99-oracle-asmdevices.rules << EOF
# ASM disk rules
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM=="/usr/lib/udev/scsi_id -g -u -d /dev/\$name", \
RESULT=="360000000000000000000000000000001", OWNER="grid", GROUP="asmadmin", MODE="0660"
EOF
# Reload UDEV rules
udevadm control --reload-rules
udevadm trigger --type=devices --action=change
Terminal window
# Scan for new SCSI devices
for host in /sys/class/scsi_host/*; do
echo "- - -" > $host/scan
done
# Check for new devices
dmesg | tail -20
lsblk
# Partition new disk
fdisk /dev/sde
# Create primary partition using full disk
# Create ASM disk
oracleasm createdisk DISK4 /dev/sde1
-- Check available disks for diskgroup creation
SELECT COUNT(*) as candidate_disks
FROM v$asm_disk
WHERE header_status = 'CANDIDATE';
-- List candidate disks
SELECT path, total_mb
FROM v$asm_disk
WHERE header_status = 'CANDIDATE'
ORDER BY path;
-- Create diskgroup with available disks
CREATE DISKGROUP data NORMAL REDUNDANCY
DISK '/dev/oracleasm/disks/DISK1',
'/dev/oracleasm/disks/DISK2',
'/dev/oracleasm/disks/DISK3';
#!/bin/bash
# Force disk discovery with permission fix
# Set ASM environment
export ORACLE_HOME=/u01/app/19.0.0/grid
export ORACLE_SID=+ASM
# Fix permissions on all potential ASM disks
for dev in /dev/sd[b-z]*; do
if [ -b "$dev" ]; then
chown grid:asmadmin "$dev"
chmod 660 "$dev"
fi
done
# Clear ASM disk cache
$ORACLE_HOME/bin/sqlplus -s / as sysasm << EOF
ALTER SYSTEM SET asm_diskstring = '' SCOPE=MEMORY;
ALTER SYSTEM SET asm_diskstring = '/dev/sd*' SCOPE=MEMORY;
EOF
# List discovered disks
$ORACLE_HOME/bin/sqlplus -s / as sysasm << EOF
COL path FORMAT A30
SELECT path, header_status, total_mb
FROM v\$asm_disk
WHERE header_status IN ('CANDIDATE', 'MEMBER')
ORDER BY path;
EOF
-- Create discovery diagnostic procedure
CREATE OR REPLACE PROCEDURE diagnose_disk_discovery AS
v_diskstring VARCHAR2(4000);
v_count NUMBER;
BEGIN
-- Get current diskstring
SELECT value INTO v_diskstring
FROM v$parameter WHERE name = 'asm_diskstring';
DBMS_OUTPUT.PUT_LINE('Current ASM_DISKSTRING: ' || v_diskstring);
DBMS_OUTPUT.PUT_LINE('==================================');
-- Count disks by status
FOR rec IN (
SELECT header_status, COUNT(*) as cnt
FROM v$asm_disk
GROUP BY header_status
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.header_status || ': ' || rec.cnt || ' disks');
END LOOP;
-- Check for specific issues
SELECT COUNT(*) INTO v_count
FROM v$asm_disk
WHERE header_status = 'CANDIDATE';
IF v_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('WARNING: No candidate disks found!');
DBMS_OUTPUT.PUT_LINE('Check:');
DBMS_OUTPUT.PUT_LINE('1. Disk permissions');
DBMS_OUTPUT.PUT_LINE('2. ASM_DISKSTRING parameter');
DBMS_OUTPUT.PUT_LINE('3. Disk provisioning');
END IF;
-- List problematic disks
DBMS_OUTPUT.PUT_LINE('==================================');
DBMS_OUTPUT.PUT_LINE('Problematic disks:');
FOR rec IN (
SELECT path, header_status
FROM v$asm_disk
WHERE header_status NOT IN ('MEMBER', 'CANDIDATE')
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.path || ' - ' || rec.header_status);
END LOOP;
END;
/
-- Execute diagnostic
SET SERVEROUTPUT ON
EXEC diagnose_disk_discovery;
#!/bin/bash
# Clear and reinitialize ASM disks
# WARNING: This destroys data!
read -p "This will destroy all data on ASM disks. Continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "Aborted."
exit 1
fi
# Stop ASM
crsctl stop resource ora.asm -f
# Clear disk headers
for disk in /dev/oracleasm/disks/*; do
echo "Clearing $disk..."
dd if=/dev/zero of=$disk bs=1M count=100
done
# Delete and recreate ASM disks
oracleasm deletedisk DISK1
oracleasm deletedisk DISK2
oracleasm deletedisk DISK3
# Recreate disks
oracleasm createdisk DISK1 /dev/sdb1
oracleasm createdisk DISK2 /dev/sdc1
oracleasm createdisk DISK3 /dev/sdd1
# Start ASM
crsctl start resource ora.asm
#!/bin/bash
# Monitor ASM disk discovery
LOG_FILE="/var/log/asm_discovery_monitor.log"
monitor_discovery() {
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Get disk counts
TOTAL=$(/u01/app/19.0.0/grid/bin/sqlplus -s / as sysasm << EOF
SET PAGESIZE 0 FEEDBACK OFF HEADING OFF
SELECT COUNT(*) FROM v\$asm_disk;
EOF
)
CANDIDATE=$(/u01/app/19.0.0/grid/bin/sqlplus -s / as sysasm << EOF
SET PAGESIZE 0 FEEDBACK OFF HEADING OFF
SELECT COUNT(*) FROM v\$asm_disk WHERE header_status = 'CANDIDATE';
EOF
)
MEMBER=$(/u01/app/19.0.0/grid/bin/sqlplus -s / as sysasm << EOF
SET PAGESIZE 0 FEEDBACK OFF HEADING OFF
SELECT COUNT(*) FROM v\$asm_disk WHERE header_status = 'MEMBER';
EOF
)
echo "$timestamp: Total=$TOTAL, Candidate=$CANDIDATE, Member=$MEMBER" >> $LOG_FILE
# Alert if no candidate disks
if [ "$CANDIDATE" -eq 0 ] && [ "$MEMBER" -eq 0 ]; then
echo "ALERT: No ASM disks discovered!" | mail -s "ASM Discovery Alert" [email protected]
fi
}
# Run monitoring
monitor_discovery
-- Create automated discovery test
CREATE OR REPLACE PROCEDURE test_disk_discovery(
p_min_disks NUMBER DEFAULT 3
) AS
v_candidate_count NUMBER;
v_member_count NUMBER;
v_total_count NUMBER;
BEGIN
-- Count disks by type
SELECT COUNT(*) INTO v_candidate_count
FROM v$asm_disk WHERE header_status = 'CANDIDATE';
SELECT COUNT(*) INTO v_member_count
FROM v$asm_disk WHERE header_status = 'MEMBER';
v_total_count := v_candidate_count + v_member_count;
-- Log results
INSERT INTO asm_discovery_log VALUES (
SYSTIMESTAMP,
v_total_count,
v_candidate_count,
v_member_count
);
-- Check minimum requirements
IF v_total_count < p_min_disks THEN
RAISE_APPLICATION_ERROR(-20001,
'Insufficient disks discovered: ' || v_total_count ||
' (minimum: ' || p_min_disks || ')');
END IF;
COMMIT;
END;
/
-- Schedule regular testing
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'TEST_ASM_DISCOVERY',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN test_disk_discovery(3); END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY',
enabled => TRUE
);
END;
/
#!/bin/bash
# Emergency disk discovery script
echo "Starting emergency ASM disk discovery..."
# 1. Stop and start ASM disk service
oracleasm stop
oracleasm start
# 2. Scan all possible locations
oracleasm scandisks
# 3. Force permission reset
find /dev -name "sd[b-z]*" -exec chown grid:asmadmin {} \;
find /dev -name "sd[b-z]*" -exec chmod 660 {} \;
# 4. Try multiple discovery strings
su - grid << 'EOF'
sqlplus / as sysasm << SQL
-- Try different discovery patterns
ALTER SYSTEM SET asm_diskstring = '/dev/sd*' SCOPE=MEMORY;
SELECT COUNT(*) as found_disks FROM v$asm_disk;
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/*' SCOPE=MEMORY;
SELECT COUNT(*) as found_disks FROM v$asm_disk;
ALTER SYSTEM SET asm_diskstring = '/dev/mapper/*' SCOPE=MEMORY;
SELECT COUNT(*) as found_disks FROM v$asm_disk;
-- Set final discovery string
ALTER SYSTEM SET asm_diskstring = '/dev/oracleasm/disks/*','/dev/sd*' SCOPE=BOTH;
SQL
EOF
echo "Emergency discovery completed"
-- Create diskgroup with minimum disks
DECLARE
v_disk_count NUMBER;
v_disk_list VARCHAR2(4000);
BEGIN
-- Find available disks
SELECT COUNT(*) INTO v_disk_count
FROM v$asm_disk
WHERE header_status = 'CANDIDATE';
IF v_disk_count = 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'No candidate disks available');
ELSIF v_disk_count = 1 THEN
-- External redundancy with 1 disk
SELECT path INTO v_disk_list
FROM v$asm_disk
WHERE header_status = 'CANDIDATE'
AND ROWNUM = 1;
EXECUTE IMMEDIATE 'CREATE DISKGROUP emergency EXTERNAL REDUNDANCY DISK ''' || v_disk_list || '''';
ELSE
-- Normal redundancy with available disks
SELECT LISTAGG('''' || path || '''', ',') WITHIN GROUP (ORDER BY path)
INTO v_disk_list
FROM (
SELECT path FROM v$asm_disk
WHERE header_status = 'CANDIDATE'
AND ROWNUM <= 3
);
EXECUTE IMMEDIATE 'CREATE DISKGROUP emergency NORMAL REDUNDANCY DISK ' || v_disk_list;
END IF;
DBMS_OUTPUT.PUT_LINE('Emergency diskgroup created with ' || v_disk_count || ' disks');
END;
/
  1. Configure comprehensive ASM_DISKSTRING patterns
  2. Standardize disk naming conventions
  3. Document disk-to-device mappings
  4. Regular discovery validation tests
  5. Monitor disk visibility continuously
  6. Implement automated discovery troubleshooting
  7. Maintain disk inventory documentation
  • ORA-15001: Diskgroup does not exist or is not mounted
  • ORA-15018: Diskgroup cannot be created
  • ORA-15020: Discovered duplicate ASM disk
  • ORA-15025: Could not open disk
  • Verify ASM_DISKSTRING includes all disk paths
  • Check disk existence at OS level
  • Confirm disk permissions (grid:asmadmin)
  • Test disk accessibility with dd command
  • Verify UDEV rules are correct
  • Check for SELinux/AppArmor restrictions
  • Scan for new disks at OS level
  • Review ASM alert log for discovery errors