summaryrefslogtreecommitdiffstats
path: root/sys/cam/ata
diff options
context:
space:
mode:
authorbrucec <brucec@FreeBSD.org>2010-10-24 16:31:57 +0000
committerbrucec <brucec@FreeBSD.org>2010-10-24 16:31:57 +0000
commit41dcd4566c627593cdaa04a32255183275a4ea8a (patch)
tree4019b8189051d088b2d67a8077bdfb792575305d /sys/cam/ata
parentd5b2b0a30ff2f9f2c524005c77d18d36f4c37565 (diff)
downloadFreeBSD-src-41dcd4566c627593cdaa04a32255183275a4ea8a.zip
FreeBSD-src-41dcd4566c627593cdaa04a32255183275a4ea8a.tar.gz
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
Diffstat (limited to 'sys/cam/ata')
-rw-r--r--sys/cam/ata/ata_da.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 8a27931..44d2fa6 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -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 howto);
#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 howto);
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_timeout", &ada_default_timeout);
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, void *arg)
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 */
OpenPOWER on IntegriCloud