# DF-3897 — WarpDrive validation accepts NumPhysDisks == 0: divide-by-zero panic in mpssas_direct_drive_io

File: `sys/dev/raid/mps/mps_sas.c` (pass 2); the missing guard lives in
`sys/dev/raid/mps/mps_config.c`, the fatal sinks are in this file.

## What

WarpDrive (direct-drive) configuration is enabled by
`mps_wd_config_pages` (`sys/dev/raid/mps/mps_config.c`), which validates the
RAID volume page 0 as:

```c
	if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
	    (raid_vol_pg0->NumPhysDisks > 8)) {     /* mps_config.c:399-400 */
		... "Direct Drive I/O will not be used" ... goto out;
	}
	...
	sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;   /* mps_config.c:412 */
	...
	sc->WD_valid_config = TRUE;                            /* mps_config.c:511 */
```

There is **no `NumPhysDisks == 0` rejection**: a RAID0 page with zero
physical disks passes the `> 8` check, `DD_num_phys_disks` becomes 0, and
`WD_valid_config` is set. Every subsequent READ/WRITE to the volume's
DevHandle enters `mpssas_direct_drive_io` (mps_sas.c:1760-1762), which
divides by it:

```c
	stripe_unit = physLBA / sc->DD_num_phys_disks;   /* mps_sas.c:2190 (6-byte CDBs) */
	stripe_unit = physLBA / sc->DD_num_phys_disks;   /* mps_sas.c:2269 (10/16-byte, low LBA) */
	stripe_unit = physLBA / sc->DD_num_phys_disks;   /* mps_sas.c:2347 (16-byte, high LBA) */
```

An integer division by zero in kernel text on x86_64 raises #DE →
`panic: integer divide by zero` (or fatal trap) on the first qualifying
I/O — an unprivileged process merely has to read() or write() a file on
the wed volume-shaped device.

Contrast: the same function *does* reject stripe-size 0 and block-size 0
explicitally (mps_config.c:428-433, 447-452) — the disk-count zero case
was simply missed. (Note stripe_size==0 → the `virtLBA &
(DD_stripe_size - 1)` masks at mps_sas.c:2185/2263 also degrade, but the
div-by-zero fires first in the zero-disk case.)

## Threat model

`NumPhysDisks` comes from the controller's own config-page DMA (firmware /
NVRAM-backed volume table), not from disk-supplied data — so this is a
malicious-or-corrupt-firmware / mis-flashed-WarpDrive scenario, or a
legitimate LSI firmware bug class (0-disk RAID0 pages have been observed
during volume teardown races). Hardware- and firmware-gated; hence Low /
speculative, but the sink is a guaranteed kernel panic.

## Build/run

`run.sh` records the hardware gate.

## Fix

Reject NumPhysDisks == 0 in the WarpDrive validation
(mps_config.c:399-400). See fix.diff.
