svn commit: r220412 - in head: share/man/man4 sys/cam/ata
Alexander Best
arundel at freebsd.org
Thu Apr 7 19:03:19 UTC 2011
On Thu Apr 7 11, Alexander Motin wrote:
> 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.
how hard would it be to support per device sysctls/tunables? i'd really like to
do:
kern.cam.ada.0.write_cache=0 (root fs)
kern.cam.ada.1.write_cache=1 (/usr, /var, etc.)
cheers.
alex
>
> 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 */
--
a13x
More information about the svn-src-head
mailing list