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"

Reply via email to