Author: brucec Date: Sun Oct 24 16:31:57 2010 New Revision: 214279 URL: http://svn.freebsd.org/changeset/base/214279
Log: Mostly revert r203420, and add similar functionality into ada(4) since the existing code caused problems with some SCSI controllers. A new sysctl kern.cam.ada.spindown_shutdown has been added that controls whether or not to spin-down disks when shutting down. Spinning down the disks unloads/parks the heads - this is much better than removing power when the disk is still spinning because otherwise an Emergency Unload occurs which may cause damage to the actuator. PR: kern/140752 Submitted by: olli Reviewed by: arundel Discussed with: mav MFC after: 2 weeks Modified: head/share/man/man4/ada.4 head/sys/cam/ata/ata_da.c head/sys/cam/cam_xpt.c head/sys/kern/kern_shutdown.c Modified: head/share/man/man4/ada.4 ============================================================================== --- head/share/man/man4/ada.4 Sun Oct 24 16:10:32 2010 (r214278) +++ head/share/man/man4/ada.4 Sun Oct 24 16:31:57 2010 (r214279) @@ -118,6 +118,9 @@ This variable determines how long the driver will wait before timing out an outstanding command. The units for this value are seconds, and the default is currently 30 seconds. +.It kern.cam.ada.spindown_shutdown +.Pp +This variable determines whether to spin-down disks when shutting down. .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 Sun Oct 24 16:10:32 2010 (r214278) +++ head/sys/cam/ata/ata_da.c Sun Oct 24 16:31:57 2010 (r214279) @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/eventhandler.h> #include <sys/malloc.h> #include <sys/cons.h> +#include <sys/reboot.h> #include <geom/geom_disk.h> #endif /* _KERNEL */ @@ -79,7 +80,8 @@ typedef enum { ADA_FLAG_CAN_TRIM = 0x080, ADA_FLAG_OPEN = 0x100, ADA_FLAG_SCTX_INIT = 0x200, - ADA_FLAG_CAN_CFA = 0x400 + ADA_FLAG_CAN_CFA = 0x400, + ADA_FLAG_CAN_POWERMGT = 0x800 } ada_flags; typedef enum { @@ -180,6 +182,10 @@ static void adashutdown(void *arg, int #define ADA_DEFAULT_SEND_ORDERED 1 #endif +#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN +#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 +#endif + /* * Most platforms map firmware geometry to actual, but some don't. If * not overridden, default to nothing. @@ -191,6 +197,7 @@ static void adashutdown(void *arg, int 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; SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); @@ -203,6 +210,9 @@ TUNABLE_INT("kern.cam.ada.default_timeou SYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, &ada_send_ordered, 0, "Send Ordered Tags"); TUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); +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); /* * ADA_ORDEREDTAG_INTERVAL determines how often, relative @@ -665,6 +675,8 @@ adaregister(struct cam_periph *periph, v softc->flags |= ADA_FLAG_CAN_48BIT; if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; + if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) + softc->flags |= ADA_FLAG_CAN_POWERMGT; if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && cgd->inq_flags & SID_CmdQue) softc->flags |= ADA_FLAG_CAN_NCQ; @@ -1227,6 +1239,56 @@ adashutdown(void * arg, int howto) /*getcount_only*/0); cam_periph_unlock(periph); } + + if (ada_spindown_shutdown == 0 || + (howto & (RB_HALT | RB_POWEROFF)) == 0) + return; + + TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + union ccb ccb; + + /* If we paniced with lock held - not recurse here. */ + if (cam_periph_owned(periph)) + continue; + 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, "spin-down\n"); + + xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); + + ccb.ccb_h.ccb_state = ADA_CCB_DUMP; + cam_fill_ataio(&ccb.ataio, + 1, + adadone, + CAM_DIR_NONE, + 0, + NULL, + 0, + ada_default_timeout*1000); + + ata_28bit_cmd(&ccb.ataio, ATA_STANDBY_IMMEDIATE, 0, 0, 0); + xpt_polled_action(&ccb); + + if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) + xpt_print(periph->path, "Spin-down disk failed\n"); + + if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb.ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + cam_periph_unlock(periph); + } } #endif /* _KERNEL */ Modified: head/sys/cam/cam_xpt.c ============================================================================== --- head/sys/cam/cam_xpt.c Sun Oct 24 16:10:32 2010 (r214278) +++ head/sys/cam/cam_xpt.c Sun Oct 24 16:31:57 2010 (r214279) @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include <sys/time.h> #include <sys/conf.h> #include <sys/fcntl.h> -#include <sys/reboot.h> #include <sys/interrupt.h> #include <sys/sbuf.h> #include <sys/taskqueue.h> @@ -153,10 +152,6 @@ static struct xpt_softc xsoftc; TUNABLE_INT("kern.cam.boot_delay", &xsoftc.boot_delay); SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, &xsoftc.boot_delay, 0, "Bus registration wait time"); -static int xpt_power_down = 0; -TUNABLE_INT("kern.cam.power_down", &xpt_power_down); -SYSCTL_INT(_kern_cam, OID_AUTO, power_down, CTLFLAG_RW, - &xpt_power_down, 0, "Power down devices on shutdown"); /* Queues for our software interrupt handler */ typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; @@ -250,7 +245,6 @@ static struct cam_ed* xpt_find_device(struct cam_et *target, lun_id_t lun_id); static void xpt_config(void *arg); static xpt_devicefunc_t xptpassannouncefunc; -static void xpt_shutdown(void *arg, int howto); static void xptaction(struct cam_sim *sim, union ccb *work_ccb); static void xptpoll(struct cam_sim *sim); static void camisr(void *); @@ -4538,12 +4532,6 @@ xpt_config(void *arg) #endif /* CAM_DEBUG_BUS */ #endif /* CAMDEBUG */ - /* Register our shutdown event handler */ - if ((EVENTHANDLER_REGISTER(shutdown_final, xpt_shutdown, - NULL, SHUTDOWN_PRI_FIRST)) == NULL) { - printf("xpt_config: failed to register shutdown event.\n"); - } - periphdriver_init(1); xpt_hold_boot(); callout_init(&xsoftc.boot_callout, 1); @@ -4625,87 +4613,6 @@ xpt_finishconfig_task(void *context, int free(context, M_CAMXPT); } -/* - * Power down all devices when we are going to power down the system. - */ -static void -xpt_shutdown_dev_done(struct cam_periph *periph, union ccb *done_ccb) -{ - - /* No-op. We're polling. */ - return; -} - -static int -xpt_shutdown_dev(struct cam_ed *device, void *arg) -{ - union ccb ccb; - struct cam_path path; - - if (device->flags & CAM_DEV_UNCONFIGURED) - return (1); - - if (device->protocol == PROTO_ATA) { - /* Only power down device if it supports power management. */ - if ((device->ident_data.support.command1 & - ATA_SUPPORT_POWERMGT) == 0) - return (1); - } else if (device->protocol != PROTO_SCSI) - return (1); - - xpt_compile_path(&path, - NULL, - device->target->bus->path_id, - device->target->target_id, - device->lun_id); - xpt_setup_ccb(&ccb.ccb_h, &path, CAM_PRIORITY_NORMAL); - if (device->protocol == PROTO_ATA) { - cam_fill_ataio(&ccb.ataio, - 1, - xpt_shutdown_dev_done, - CAM_DIR_NONE, - 0, - NULL, - 0, - 30*1000); - ata_28bit_cmd(&ccb.ataio, ATA_SLEEP, 0, 0, 0); - } else { - scsi_start_stop(&ccb.csio, - /*retries*/1, - xpt_shutdown_dev_done, - MSG_SIMPLE_Q_TAG, - /*start*/FALSE, - /*load/eject*/FALSE, - /*immediate*/TRUE, - SSD_FULL_SIZE, - /*timeout*/50*1000); - } - xpt_polled_action(&ccb); - - if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) - xpt_print(&path, "Device power down failed\n"); - if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) - cam_release_devq(ccb.ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); - xpt_release_path(&path); - return (1); -} - -static void -xpt_shutdown(void * arg, int howto) -{ - - if (!xpt_power_down) - return; - if ((howto & RB_POWEROFF) == 0) - return; - - xpt_for_all_devices(xpt_shutdown_dev, NULL); -} - cam_status xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, struct cam_path *path) Modified: head/sys/kern/kern_shutdown.c ============================================================================== --- head/sys/kern/kern_shutdown.c Sun Oct 24 16:10:32 2010 (r214278) +++ head/sys/kern/kern_shutdown.c Sun Oct 24 16:31:57 2010 (r214279) @@ -144,7 +144,7 @@ shutdown_conf(void *unused) { EVENTHANDLER_REGISTER(shutdown_final, poweroff_wait, NULL, - SHUTDOWN_PRI_FIRST + 100); + SHUTDOWN_PRI_FIRST); EVENTHANDLER_REGISTER(shutdown_final, shutdown_halt, NULL, SHUTDOWN_PRI_LAST + 100); EVENTHANDLER_REGISTER(shutdown_final, shutdown_panic, NULL, _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"