--- a/sys/dev/virtual/vmware/pvscsi/pvscsi.c +++ b/sys/dev/virtual/vmware/pvscsi/pvscsi.c @@ -201,6 +201,8 @@ struct pvscsi_ring_cmp_desc *cmp_ring; struct pvscsi_ring_msg_desc *msg_ring; uint32_t hcb_cnt; + /* number of hcbs whose per-hcb DMA resources exist */ + uint32_t hcbs_setup; struct pvscsi_hcb *hcbs; SLIST_HEAD(, pvscsi_hcb) free_list; bus_dma_tag_t parent_dmat; @@ -611,10 +613,15 @@ hcb = sc->hcbs + i; SLIST_INSERT_HEAD(&sc->free_list, hcb, links); } + sc->hcbs_setup = sc->hcb_cnt; fail: if (error) { + /* per-hcb resources for [0..i) were just freed above; zero + * hcbs_setup so pvscsi_free_all() does not destroy those + * maps again (double kfree in bus_dmamap_destroy) */ pvscsi_dma_free_per_hcb(sc, i); + sc->hcbs_setup = 0; } return (error); @@ -1583,7 +1590,9 @@ cam_sim_free(sc->sim); } - pvscsi_dma_free_per_hcb(sc, sc->hcb_cnt); + /* when sc->hcbs == NULL (hcb array alloc failed) hcbs_setup is 0, so + * we never callout_drain()/bus_dmamap_destroy() through a NULL base */ + pvscsi_dma_free_per_hcb(sc, sc->hcbs_setup); if (sc->hcbs) { kfree(sc->hcbs, M_PVSCSI);