From owner-svn-src-all@FreeBSD.ORG Fri Apr 15 07:07:29 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 592181065769; Fri, 15 Apr 2011 07:07:29 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 472DD8FC0A; Fri, 15 Apr 2011 07:07:29 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p3F77TxR061607; Fri, 15 Apr 2011 07:07:29 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p3F77TsC061605; Fri, 15 Apr 2011 07:07:29 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201104150707.p3F77TsC061605@svn.freebsd.org> From: Alexander Motin Date: Fri, 15 Apr 2011 07:07:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r220650 - head/sys/cam/ata X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Apr 2011 07:07:29 -0000 Author: mav Date: Fri Apr 15 07:07:29 2011 New Revision: 220650 URL: http://svn.freebsd.org/changeset/base/220650 Log: Make ada(4) driver put ATA disks into sleep state on suspend. Submitted by: jkim (original version) Modified: head/sys/cam/ata/ata_da.c Modified: head/sys/cam/ata/ata_da.c ============================================================================== --- head/sys/cam/ata/ata_da.c Fri Apr 15 03:09:27 2011 (r220649) +++ head/sys/cam/ata/ata_da.c Fri Apr 15 07:07:29 2011 (r220650) @@ -180,6 +180,8 @@ static void adagetparams(struct cam_per struct ccb_getdev *cgd); static timeout_t adasendorderedtag; static void adashutdown(void *arg, int howto); +static void adasuspend(void *arg); +static void adaresume(void *arg); #ifndef ADA_DEFAULT_TIMEOUT #define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ @@ -197,6 +199,10 @@ static void adashutdown(void *arg, int #define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 #endif +#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND +#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 +#endif + #ifndef ADA_DEFAULT_WRITE_CACHE #define ADA_DEFAULT_WRITE_CACHE 1 #endif @@ -213,6 +219,7 @@ static int ada_retry_count = ADA_DEFAULT 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; static int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, @@ -229,6 +236,9 @@ TUNABLE_INT("kern.cam.ada.ada_send_order 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); SYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, &ada_write_cache, 0, "Enable disk write cache"); TUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); @@ -525,8 +535,14 @@ 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(power_resume, adaresume, + 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"); } @@ -1372,7 +1388,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; @@ -1424,10 +1440,13 @@ adashutdown(void * arg, int howto) /*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, int flags) +{ + struct cam_periph *periph; + struct ada_softc *softc; TAILQ_FOREACH(periph, &adadriver.units, unit_links) { union ccb ccb; @@ -1454,13 +1473,13 @@ adashutdown(void * arg, int howto) cam_fill_ataio(&ccb.ataio, 1, adadone, - CAM_DIR_NONE, + CAM_DIR_NONE | flags, 0, NULL, 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) @@ -1476,4 +1495,60 @@ adashutdown(void * arg, int howto) } } +static void +adashutdown(void *arg, int howto) +{ + + adaflush(); + if (ada_spindown_shutdown != 0 && + (howto & (RB_HALT | RB_POWEROFF)) != 0) + adaspindown(ATA_STANDBY_IMMEDIATE, 0); +} + +static void +adasuspend(void *arg) +{ + + adaflush(); + if (ada_spindown_suspend != 0) + adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); +} + +static void +adaresume(void *arg) +{ + struct cam_periph *periph; + struct ada_softc *softc; + + if (ada_spindown_suspend == 0) + return; + + TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + cam_periph_lock(periph); + softc = (struct ada_softc *)periph->softc; + /* + * We only spin-down the drive if it is capable of it.. + */ + if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { + cam_periph_unlock(periph); + continue; + } + + if (bootverbose) + xpt_print(periph->path, "resume\n"); + + /* + * Drop freeze taken due to CAM_DEV_QFREEZE flag set on + * sleep request. + */ + cam_release_devq(periph->path, + /*relsim_flags*/0, + /*openings*/0, + /*timeout*/0, + /*getcount_only*/0); + + cam_periph_unlock(periph); + } +} + #endif /* _KERNEL */