Index: sys/cam/ata/ata_da.c =================================================================== --- sys/cam/ata/ata_da.c (revision 217032) +++ sys/cam/ata/ata_da.c (working copy) @@ -169,6 +169,7 @@ static void adagetparams(struct cam_periph *perip struct ccb_getdev *cgd); static timeout_t adasendorderedtag; static void adashutdown(void *arg, int howto); +static void adasuspend(void *arg); #ifndef ADA_DEFAULT_TIMEOUT #define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ @@ -186,6 +187,10 @@ static void adashutdown(void *arg, int howto); #define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 #endif +#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND +#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 +#endif + /* * Most platforms map firmware geometry to actual, but some don't. If * not overridden, default to nothing. @@ -198,6 +203,7 @@ static int ada_retry_count = ADA_DEFAULT_RETRY; static int ada_default_timeout = ADA_DEFAULT_TIMEOUT; static int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; static int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; +static int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); @@ -213,6 +219,9 @@ TUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_ SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, &ada_spindown_shutdown, 0, "Spin down upon shutdown"); TUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); +SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, + &ada_spindown_suspend, 0, "Spin down upon suspend"); +TUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); /* * ADA_ORDEREDTAG_INTERVAL determines how often, relative @@ -506,8 +515,11 @@ adainit(void) "due to status 0x%x!\n", status); } else if (ada_send_ordered) { - /* Register our shutdown event handler */ - if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, + /* Register our event handlers */ + if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, + NULL, EVENTHANDLER_PRI_LAST)) == NULL) + printf("adainit: power event registration failed!\n"); + if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) printf("adainit: shutdown event registration failed!\n"); } @@ -1187,7 +1199,7 @@ adasendorderedtag(void *arg) * sync the disk cache to physical media. */ static void -adashutdown(void * arg, int howto) +adaflush(void) { struct cam_periph *periph; struct ada_softc *softc; @@ -1239,10 +1251,13 @@ static void /*getcount_only*/0); cam_periph_unlock(periph); } +} - if (ada_spindown_shutdown == 0 || - (howto & (RB_HALT | RB_POWEROFF)) == 0) - return; +static void +adaspindown(uint8_t cmd) +{ + struct cam_periph *periph; + struct ada_softc *softc; TAILQ_FOREACH(periph, &adadriver.units, unit_links) { union ccb ccb; @@ -1275,7 +1290,7 @@ static void 0, ada_default_timeout*1000); - ata_28bit_cmd(&ccb.ataio, ATA_STANDBY_IMMEDIATE, 0, 0, 0); + ata_28bit_cmd(&ccb.ataio, cmd, 0, 0, 0); xpt_polled_action(&ccb); if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) @@ -1291,4 +1306,23 @@ static void } } +static void +adashutdown(void *arg, int howto) +{ + + adaflush(); + if (ada_spindown_shutdown != 0 && + (howto & (RB_HALT | RB_POWEROFF)) != 0) + adaspindown(ATA_STANDBY_IMMEDIATE); +} + +static void +adasuspend(void *arg) +{ + + adaflush(); + if (ada_spindown_suspend != 0) + adaspindown(ATA_SLEEP); +} + #endif /* _KERNEL */ Index: sys/dev/acpica/acpi.c =================================================================== --- sys/dev/acpica/acpi.c (revision 217032) +++ sys/dev/acpica/acpi.c (working copy) @@ -2609,6 +2609,8 @@ acpi_EnterSleepState(struct acpi_softc *sc, int st return_ACPI_STATUS (AE_OK); } + EVENTHANDLER_INVOKE(power_suspend); + if (smp_started) { thread_lock(curthread); sched_bind(curthread, 0); @@ -2700,6 +2702,8 @@ backout: thread_unlock(curthread); } + EVENTHANDLER_INVOKE(power_resume); + /* Allow another sleep request after a while. */ timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); Index: sys/dev/siis/siis.c =================================================================== --- sys/dev/siis/siis.c (revision 217032) +++ sys/dev/siis/siis.c (working copy) @@ -589,8 +589,6 @@ siis_ch_suspend(device_t dev) mtx_lock(&ch->mtx); xpt_freeze_simq(ch->sim, 1); - while (ch->oslots) - msleep(ch, &ch->mtx, PRIBIO, "siissusp", hz/100); siis_ch_deinit(dev); mtx_unlock(&ch->mtx); return (0); Index: sys/dev/ahci/ahci.c =================================================================== --- sys/dev/ahci/ahci.c (revision 217032) +++ sys/dev/ahci/ahci.c (working copy) @@ -1056,8 +1056,6 @@ ahci_ch_suspend(device_t dev) mtx_lock(&ch->mtx); xpt_freeze_simq(ch->sim, 1); - while (ch->oslots) - msleep(ch, &ch->mtx, PRIBIO, "ahcisusp", hz/100); ahci_ch_deinit(dev); mtx_unlock(&ch->mtx); return (0); Index: sys/dev/mvs/mvs.c =================================================================== --- sys/dev/mvs/mvs.c (revision 217032) +++ sys/dev/mvs/mvs.c (working copy) @@ -276,8 +276,6 @@ mvs_ch_suspend(device_t dev) mtx_lock(&ch->mtx); xpt_freeze_simq(ch->sim, 1); - while (ch->oslots) - msleep(ch, &ch->mtx, PRIBIO, "mvssusp", hz/100); mvs_ch_deinit(dev); mtx_unlock(&ch->mtx); return (0); Index: sys/dev/ata/ata-all.c =================================================================== --- sys/dev/ata/ata-all.c (revision 217032) +++ sys/dev/ata/ata-all.c (working copy) @@ -472,8 +472,6 @@ ata_suspend(device_t dev) #ifdef ATA_CAM mtx_lock(&ch->state_mtx); xpt_freeze_simq(ch->sim, 1); - while (ch->state != ATA_IDLE) - msleep(ch, &ch->state_mtx, PRIBIO, "atasusp", hz/100); mtx_unlock(&ch->state_mtx); #else /* wait for the channel to be IDLE or detached before suspending */ Index: sys/sys/eventhandler.h =================================================================== --- sys/sys/eventhandler.h (revision 217032) +++ sys/sys/eventhandler.h (working copy) @@ -178,6 +178,11 @@ EVENTHANDLER_DECLARE(shutdown_pre_sync, shutdown_f EVENTHANDLER_DECLARE(shutdown_post_sync, shutdown_fn); /* after fs sync */ EVENTHANDLER_DECLARE(shutdown_final, shutdown_fn); +/* Power state change events */ +typedef void (*power_change_fn)(void *); +EVENTHANDLER_DECLARE(power_resume, power_change_fn); +EVENTHANDLER_DECLARE(power_suspend, power_change_fn); + /* Low memory event */ typedef void (*vm_lowmem_handler_t)(void *, int); #define LOWMEM_PRI_DEFAULT EVENTHANDLER_PRI_FIRST