diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index c700e7c5d1d4..e929e518506f 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -1835,7 +1835,7 @@ adaflush(void) struct ada_softc *softc; int error; - TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &adadriver) { union ccb ccb; /* If we paniced with lock held - not recurse here. */ @@ -1889,7 +1889,7 @@ adaspindown(uint8_t cmd, int flags) struct ada_softc *softc; int error; - TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &adadriver) { union ccb ccb; /* If we paniced with lock held - not recurse here. */ @@ -1962,7 +1962,7 @@ adaresume(void *arg) if (ada_spindown_suspend == 0) return; - TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &adadriver) { cam_periph_lock(periph); softc = (struct ada_softc *)periph->softc; /* diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h index b51fb681b2d3..bd378ec8afd1 100644 --- a/sys/cam/cam_periph.h +++ b/sys/cam/cam_periph.h @@ -183,6 +183,8 @@ void cam_periph_freeze_after_event(struct cam_periph *periph, u_int duration_ms); int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags, union ccb *save_ccb); +void xpt_lock_buses(void); +void xpt_unlock_buses(void); static __inline void cam_periph_lock(struct cam_periph *periph) @@ -209,5 +211,42 @@ cam_periph_sleep(struct cam_periph *periph, void *chan, int priority, return (msleep(chan, periph->sim->mtx, priority, wmesg, timo)); } +static inline struct cam_periph * +cam_periph_acquire_first(struct periph_driver *driver) +{ + struct cam_periph *periph; + + xpt_lock_buses(); + periph = TAILQ_FIRST(&driver->units); + while (periph != NULL && (periph->flags & CAM_PERIPH_INVALID) != 0) + periph = TAILQ_NEXT(periph, unit_links); + if (periph != NULL) + periph->refcount++; + xpt_unlock_buses(); + return (periph); +} + +static inline struct cam_periph * +cam_periph_acquire_next(struct cam_periph *pperiph) +{ + struct cam_periph *periph = pperiph; + + mtx_assert(pperiph->sim->mtx, MA_NOTOWNED); + xpt_lock_buses(); + do { + periph = TAILQ_NEXT(periph, unit_links); + } while (periph != NULL && (periph->flags & CAM_PERIPH_INVALID) != 0); + if (periph != NULL) + periph->refcount++; + xpt_unlock_buses(); + cam_periph_release(pperiph); + return (periph); +} + +#define CAM_PERIPH_FOREACH(periph, driver) \ + for ((periph) = cam_periph_acquire_first(driver); \ + (periph) != NULL; \ + (periph) = cam_periph_acquire_next(periph)) + #endif /* _KERNEL */ #endif /* _CAM_CAM_PERIPH_H */ diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 9fd7039b8781..aaa2a4c42e25 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -2848,7 +2848,7 @@ dashutdown(void * arg, int howto) struct da_softc *softc; int error; - TAILQ_FOREACH(periph, &dadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &dadriver) { union ccb ccb; cam_periph_lock(periph);