I eventually got around to hack scsi_da.c to implement spin down/up on
suspend/resume events of APM or ACPI.  Actually the ACPI stuff is
untested and the APM once didn't work properly on my system: one of
the disks, after resume, was misbehaving (hardware errors).  A power
toggle fixed the problem, though.

I suspect this code could be improved introducing a delay after the
spin up of each HD (I've got 6 HD hooked to a 350W power supply, this
might explain the hardware error), but not being a kernel hacker
myself, I don't know how to proceed.  Suggestions are welcome.

Please note you need to define CAM_APM_COOP or CAM_ACPI_COOP.


--- scsi_da.c.orig      Mon Nov  3 00:15:55 2003
+++ scsi_da.c   Mon Nov  3 00:18:04 2003
@@ -72,6 +72,15 @@
 #include <cam/scsi/scsi_da.h>
 #endif /* !_KERNEL */
 
+#ifdef CAM_ACPI_COOP
+# include <sys/bus.h>
+# include <dev/acpica/acpica_support.h>
+# include <dev/acpica/acpivar.h>
+#endif /* CAM_ACPI_COOP */
+#ifdef CAM_APM_COOP
+# include <machine/apm_bios.h>
+#endif
+
 #ifdef _KERNEL
 typedef enum {
        DA_STATE_PROBE,
@@ -142,6 +151,40 @@
        da_quirks quirks;
 };
 
+#ifdef CAM_APM_COOP
+static void da_start_stop_all(int start);
+
+static int
+da_apm_suspend (void *junk)
+{
+       da_start_stop_all (0);
+       return 0;
+}
+
+static int
+da_apm_resume (void *junk)
+{
+       da_start_stop_all (1);
+       return 0;
+}
+
+struct apmhook da_suspend_hook = {
+       0,                      /* next */
+       da_apm_suspend,         /* fun */
+       0,                      /* arg */
+       "da_suspend",           /* name */
+       0                       /* order */
+};
+
+struct apmhook da_resume_hook = {
+       0,                      /* next */
+       da_apm_resume,          /* fun */
+       0,                      /* arg */
+       "da_resume",            /* name */
+       0                       /* order */
+};
+#endif /* CAM_APM_COOP */
+
 static const char quantum[] = "QUANTUM";
 static const char microp[] = "MICROP";
 
@@ -213,6 +256,12 @@
                {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS525S", "*"},
                /*quirks*/ DA_Q_NO_SYNC_CACHE
        },
+       {       {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS540S", "*"},
+               DA_Q_NO_SYNC_CACHE },
+       {       {T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CP3500*", "*"},
+               DA_Q_NO_SYNC_CACHE },
+       {       {T_DIRECT, SIP_MEDIA_REMOVABLE, "DataFab*", "*", "*"},
+               DA_Q_NO_6_BYTE | DA_Q_NO_SYNC_CACHE },
        {
                /*
                 * Doesn't work correctly with 6 byte reads/writes.
@@ -935,6 +984,71 @@
        return (0);
 }
 
+/*
+ * Step through all DA peripheral drivers and spin them up/down.
+ */
+static void
+da_start_stop_all(int start)
+{
+       struct cam_periph *periph;
+       struct da_softc *softc;
+
+       for (periph = TAILQ_FIRST(&dadriver.units); periph != NULL;
+            periph = TAILQ_NEXT(periph, unit_links)) {
+               union ccb ccb;
+               softc = (struct da_softc *)periph->softc;
+
+               xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1);
+
+               ccb.ccb_h.ccb_state = DA_CCB_DUMP;
+               scsi_start_stop(&ccb.csio,
+                               /*retries*/1,
+                               /*cbfcnp*/dadone,
+                               MSG_SIMPLE_Q_TAG,
+                               start,
+                               /*load_eject*/ 0,
+                               /*immediate*/ FALSE,
+                               /*sense_len*/ SSD_FULL_SIZE,
+                               /*timeout*/ 50000);
+
+               xpt_polled_action(&ccb);
+
+               if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+                       if (((ccb.ccb_h.status & CAM_STATUS_MASK) ==
+                            CAM_SCSI_STATUS_ERROR)
+                        && (ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND)){
+                               int error_code, sense_key, asc, ascq;
+
+                               scsi_extract_sense(&ccb.csio.sense_data,
+                                                  &error_code, &sense_key,
+                                                  &asc, &ascq);
+
+                               if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
+                                       scsi_sense_print(&ccb.csio);
+                       } else {
+                               xpt_print_path(periph->path);
+                               printf("Suspend disk failed, status "
+                                      "== 0x%x, scsi status == 0x%x\n",
+                                      ccb.ccb_h.status, ccb.csio.scsi_status);
+                       }
+               }
+       }
+}
+
+#ifdef CAM_ACPI_COOP
+static void
+da_start_all(void *arg, int state)
+{
+       da_start_stop_all(1);
+}
+
+static void
+da_stop_all(void *arg, int state)
+{
+       da_start_stop_all(0);
+}
+#endif /* CAM_ACPI_COOP */
+
 static void
 dainit(void)
 {
@@ -987,6 +1101,14 @@
                if ((EVENTHANDLER_REGISTER(shutdown_post_sync, dashutdown, 
                                           NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
                    printf("dainit: shutdown event registration failed!\n");
+#ifdef CAM_ACPI_COOP
+               EVENTHANDLER_REGISTER(acpi_sleep_event, da_stop_all, NULL, 
ACPI_EVENT_PRI_DEFAULT);
+               EVENTHANDLER_REGISTER(acpi_wakeup_event, da_start_all, NULL, 
ACPI_EVENT_PRI_DEFAULT);
+#endif
+#ifdef CAM_APM_COOP
+               apm_hook_establish (APM_HOOK_SUSPEND, &da_suspend_hook);
+               apm_hook_establish (APM_HOOK_RESUME, &da_resume_hook);
+#endif
        }
 }
 


-- 
walter pelissero
http://www.pelissero.de
_______________________________________________
[EMAIL PROTECTED] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to