diff --git a/sys/dev/disk/nata/chipsets/ata-serverworks.c b/sys/dev/disk/nata/chipsets/ata-serverworks.c --- a/sys/dev/disk/nata/chipsets/ata-serverworks.c +++ b/sys/dev/disk/nata/chipsets/ata-serverworks.c @@ -216,7 +216,8 @@ if (atadev->flags & ATA_D_USE_CHS) { int heads, sectors; - if (atadev->param.atavalid & ATA_FLAG_54_58) { + if ((atadev->param.atavalid & ATA_FLAG_54_58) && + atadev->param.current_heads && atadev->param.current_sectors) { heads = atadev->param.current_heads; sectors = atadev->param.current_sectors; } @@ -225,6 +226,18 @@ sectors = atadev->param.sectors; } + /* Defense-in-depth (DF-2069): IDENTIFY words 54-58 may legitimately + * advertise ATA_FLAG_54_58 validity but report a zero geometry + * (observed on misbehaving/emulated ATA devices). Without this + * guard the divisions below trigger a kernel divide-by-zero trap. + * ata-disk.c:ad_invalidate() applies the identical + * (current_heads && current_sectors) check before adopting the + * current_* geometry; this write path previously did not. */ + if (heads == 0 || sectors == 0) { + request->result = EIO; + return; + } + ATA_IDX_OUTW(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1); ATA_IDX_OUTW(ch, ATA_CYL_LSB, (request->u.ata.lba / (sectors * heads)));