From owner-svn-src-all@FreeBSD.ORG Thu Apr 7 08:17:53 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 B92FC106566B; Thu, 7 Apr 2011 08:17:53 +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 A89C18FC16; Thu, 7 Apr 2011 08:17:53 +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 p378Hrvk033574; Thu, 7 Apr 2011 08:17:53 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p378HrHc033571; Thu, 7 Apr 2011 08:17:53 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201104070817.p378HrHc033571@svn.freebsd.org> From: Alexander Motin Date: Thu, 7 Apr 2011 08:17:53 +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: r220412 - in head: share/man/man4 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: Thu, 07 Apr 2011 08:17:53 -0000 Author: mav Date: Thu Apr 7 08:17:53 2011 New Revision: 220412 URL: http://svn.freebsd.org/changeset/base/220412 Log: Make ada(4) driver to control device write cache, same as ata(4) does. Add kern.cam.ada.write_cache sysctl/tunable to control it alike hw.ata.wc. Modified: head/share/man/man4/ada.4 head/sys/cam/ata/ata_da.c Modified: head/share/man/man4/ada.4 ============================================================================== --- head/share/man/man4/ada.4 Thu Apr 7 07:34:01 2011 (r220411) +++ head/share/man/man4/ada.4 Thu Apr 7 08:17:53 2011 (r220412) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 24, 2010 +.Dd April 7, 2011 .Dt ADA 4 .Os .Sh NAME @@ -123,6 +123,11 @@ seconds. This variable determines whether to spin-down disks when shutting down. Set to 1 to enable spin-down, 0 to disable. The default is currently enabled. +.It kern.cam.ada.write_cache +.Pp +This variable determines whether device write cache should be enabled or not. +Set to 1 to enable write cache, 0 to disable, -1 to left it as-is. +The default is currently enabled. .El .Sh FILES .Bl -tag -width ".Pa /dev/ada*" -compact Modified: head/sys/cam/ata/ata_da.c ============================================================================== --- head/sys/cam/ata/ata_da.c Thu Apr 7 07:34:01 2011 (r220411) +++ head/sys/cam/ata/ata_da.c Thu Apr 7 08:17:53 2011 (r220412) @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #define ATA_MAX_28BIT_LBA 268435455UL typedef enum { + ADA_STATE_WCACHE, ADA_STATE_NORMAL } ada_state; @@ -89,6 +90,7 @@ typedef enum { } ada_quirks; typedef enum { + ADA_CCB_WCACHE = 0x01, ADA_CCB_BUFFER_IO = 0x03, ADA_CCB_WAITING = 0x04, ADA_CCB_DUMP = 0x05, @@ -186,6 +188,10 @@ static void adashutdown(void *arg, int #define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 #endif +#ifndef ADA_DEFAULT_WRITE_CACHE +#define ADA_DEFAULT_WRITE_CACHE 1 +#endif + /* * Most platforms map firmware geometry to actual, but some don't. If * not overridden, default to nothing. @@ -198,6 +204,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_write_cache = ADA_DEFAULT_WRITE_CACHE; SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); @@ -213,6 +220,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, write_cache, CTLFLAG_RW, + &ada_write_cache, 0, "Enable disk write cache"); +TUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); /* * ADA_ORDEREDTAG_INTERVAL determines how often, relative @@ -568,6 +578,7 @@ adaasync(void *callback_arg, u_int32_t c struct cam_path *path, void *arg) { struct cam_periph *periph; + struct ada_softc *softc; periph = (struct cam_periph *)callback_arg; switch (code) { @@ -600,6 +611,28 @@ adaasync(void *callback_arg, u_int32_t c "due to status 0x%x\n", status); break; } + case AC_SENT_BDR: + case AC_BUS_RESET: + { + struct ccb_getdev cgd; + + softc = (struct ada_softc *)periph->softc; + cam_periph_async(periph, code, path, arg); + if (ada_write_cache < 0) + break; + if (softc->state != ADA_STATE_NORMAL) + break; + xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + if ((cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) == 0) + break; + softc->state = ADA_STATE_WCACHE; + cam_periph_acquire(periph); + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); + xpt_schedule(periph, CAM_PRIORITY_DEV); + } default: cam_periph_async(periph, code, path, arg); break; @@ -691,7 +724,6 @@ adaregister(struct cam_periph *periph, v } if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) softc->flags |= ADA_FLAG_CAN_CFA; - softc->state = ADA_STATE_NORMAL; periph->softc = softc; @@ -788,7 +820,7 @@ adaregister(struct cam_periph *periph, v * them and the only alternative would be to * not attach the device on failure. */ - xpt_register_async(AC_LOST_DEVICE, + xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, adaasync, periph, periph->path); /* @@ -800,6 +832,16 @@ adaregister(struct cam_periph *periph, v (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, adasendorderedtag, softc); + if (ada_write_cache >= 0 && + cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { + softc->state = ADA_STATE_WCACHE; + cam_periph_acquire(periph); + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); + xpt_schedule(periph, CAM_PRIORITY_DEV); + } else + softc->state = ADA_STATE_NORMAL; + return(CAM_REQ_CMP); } @@ -1009,6 +1051,23 @@ out: adaschedule(periph); break; } + case ADA_STATE_WCACHE: + { + cam_fill_ataio(ataio, + 1, + adadone, + CAM_DIR_NONE, + 0, + NULL, + 0, + ada_default_timeout*1000); + + ata_28bit_cmd(ataio, ATA_SETFEATURES, ada_write_cache ? + ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); + start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; + xpt_action(start_ccb); + break; + } } } @@ -1097,6 +1156,36 @@ adadone(struct cam_periph *periph, union biodone(bp); break; } + case ADA_CCB_WCACHE: + { + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (adaerror(done_ccb, 0, 0) == ERESTART) { + return; + } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + } + } + + softc->state = ADA_STATE_NORMAL; + /* + * Since our peripheral may be invalidated by an error + * above or an external event, we must release our CCB + * before releasing the reference on the peripheral. + * The peripheral will only go away once the last reference + * is removed, and we need it around for the CCB release + * operation. + */ + xpt_release_ccb(done_ccb); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); + adaschedule(periph); + cam_periph_release_locked(periph); + return; + } case ADA_CCB_WAITING: { /* Caller will release the CCB */