diff --git a/sys/bus/cam/scsi/scsi_da.c b/sys/bus/cam/scsi/scsi_da.c --- a/sys/bus/cam/scsi/scsi_da.c +++ b/sys/bus/cam/scsi/scsi_da.c @@ -353,7 +353,7 @@ static void daprevent(struct cam_periph *periph, int action); static int dagetcapacity(struct cam_periph *periph, int ccbflags); static int dacheckmedia(struct cam_periph *periph); -static void dasetgeom(struct cam_periph *periph, uint32_t block_len, +static int dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector); static void daflushbioq(struct bio_queue_head *bioq, int error); static void dashutdown(void *arg, int howto); @@ -2276,7 +2276,7 @@ return (error); } -static void +static int dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector) { struct ccb_calc_geometry *ccg; @@ -2285,6 +2285,17 @@ softc = (struct da_softc *)periph->softc; + /* + * A block size of zero from READ CAPACITY is nonsensical and would + * cause divide-by-zero traps everywhere the driver (and every SIM's + * XPT_CALC_GEOMETRY handler) divide by secsize. Reject it rather + * than caching a value that crashes the kernel on the next I/O. + */ + if (block_len == 0) { + xpt_print(periph->path, "READ CAPACITY returned 0 block size\n"); + return (EINVAL); + } + dp = &softc->params; dp->secsize = block_len; dp->sectors = maxsector + 1; @@ -2323,6 +2334,8 @@ dp->cylinders = ccg->cylinders; } xpt_free_ccb(&ccg->ccb_h); + + return (0); } /*