diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -2518,7 +2518,16 @@ error = ada_zone_cmd(periph, start_ccb, bp, &queue_ccb); if ((error != 0) || (queue_ccb == 0)) { + /* + * g_io_deliver will recurisvely call start + * routine for ENOMEM, so drop the periph + * lock to allow that recursion. + */ + if (error == ENOMEM) + cam_periph_unlock(periph); biofinish(bp, NULL, error); + if (error == ENOMEM) + cam_periph_lock(periph); xpt_release_ccb(start_ccb); return; } diff --git a/sys/cam/nvme/nvme_da.c b/sys/cam/nvme/nvme_da.c --- a/sys/cam/nvme/nvme_da.c +++ b/sys/cam/nvme/nvme_da.c @@ -1077,7 +1077,17 @@ trim = malloc(sizeof(*trim), M_NVMEDA, M_ZERO | M_NOWAIT); if (trim == NULL) { + /* + * We have to drop the periph lock when + * returning ENOMEM. g_io_deliver treats these + * request differently and will recursively call + * the start routine which causes us to get into + * ndastrategy with the periph lock held, + * leading to a panic when its acquired again. + */ + cam_periph_unlock(periph); biofinish(bp, NULL, ENOMEM); + cam_periph_lock(periph); xpt_release_ccb(start_ccb); ndaschedule(periph); return; diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -3455,10 +3455,19 @@ queue_ccb = 0; - error = da_zone_cmd(periph, start_ccb, bp,&queue_ccb); + error = da_zone_cmd(periph, start_ccb, bp, &queue_ccb); if ((error != 0) || (queue_ccb == 0)) { + /* + * g_io_deliver will recurisvely call start + * routine for ENOMEM, so drop the periph + * lock to allow that recursion. + */ + if (error == ENOMEM) + cam_periph_unlock(periph); biofinish(bp, NULL, error); + if (error == ENOMEM) + cam_periph_lock(periph); xpt_release_ccb(start_ccb); return; }