The sysvinit team (or at least the one member who had time to reply)
has given me their nod to go ahead and request this update for
etchnhalf.

The issue this resolves and the fix is best described here:
 http://linux-ata.org/shutdown.html

This patch has been in sysvinit since 2.86.ds1-40, first entering
unstable in 2.86.ds1-47 on 2007.12.31 and into testing on 2008.01.11
with no known regressions.

Testing of this update has been performed on both etch and etchnhalf
kernels, on both an IDE system and one that uses libata:
 http://teams.debian.net/lurker/message/20080430.232539.ef917353.en.html

May I upload to p-u?

diff -u sysvinit-2.86.ds1/debian/patches/00list 
sysvinit-2.86.ds1/debian/patches/00list
--- sysvinit-2.86.ds1/debian/patches/00list
+++ sysvinit-2.86.ds1/debian/patches/00list
@@ -35,0 +36 @@
+92_sata-hddown
diff -u sysvinit-2.86.ds1/debian/changelog sysvinit-2.86.ds1/debian/changelog
--- sysvinit-2.86.ds1/debian/changelog
+++ sysvinit-2.86.ds1/debian/changelog
@@ -1,3 +1,11 @@
+sysvinit (2.86.ds1-38+etchnhalf.1) UNRELEASED; urgency=high
+
+  * Include patch from Werner Fink at SuSe to handle each disk individually
+    and automatically instead of guessing in the init.d script how
+    to handle them collectively (Closes: #426224).
+
+ -- dann frazier <[EMAIL PROTECTED]>  Wed, 09 Apr 2008 16:18:20 -0600
+
 sysvinit (2.86.ds1-38) unstable; urgency=medium
 
   * Medium urgency as it solve an RC bug in etch.
only in patch2:
unchanged:
--- sysvinit-2.86.ds1.orig/debian/patches/92_sata-hddown.dpatch
+++ sysvinit-2.86.ds1/debian/patches/92_sata-hddown.dpatch
@@ -0,0 +1,357 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 92_sata-hddown.dpatch by Werner Fink and SuSe
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Make sure to shut down SATA disks properly, and handle each
+## DP: disk individually.  See also http://linux-ata.org/shutdown.html
+
[EMAIL PROTECTED]@
+diff -urNad trunk~/src/hddown.c trunk/src/hddown.c
+--- trunk~/src/hddown.c        2008-03-26 09:32:51.000000000 +0100
++++ trunk/src/hddown.c 2008-03-26 09:32:51.000000000 +0100
+@@ -5,6 +5,9 @@
+  */
+ char *v_hddown = "@(#)hddown.c  1.02  22-Apr-2003  [EMAIL PROTECTED]";
+ 
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE
++#endif
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+@@ -18,6 +21,326 @@
+ #include <sys/ioctl.h>
+ #include <linux/hdreg.h>
+ 
++#define USE_SYSFS
++#ifdef USE_SYSFS
++/*
++ * sysfs part Find all disks on the system, list out IDE and unmanaged
++ *            SATA disks, flush the cache of those and shut them down.
++ * Author:    Werner Fink <[EMAIL PROTECTED]>, 2007/06/12
++ *
++ */
++#include <limits.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#ifdef WORDS_BIGENDIAN
++#include <byteswap.h>
++#endif
++
++#define SYS_BLK               "/sys/block"
++#define SYS_CLASS     "/sys/class/scsi_disk"
++#define DEV_BASE      "/dev"
++#define ISSPACE(c)    (((c)==' 
')||((c)=='\n')||((c)=='\t')||((c)=='\v')||((c)=='\r')||((c)=='\f'))
++
++/* Used in flush_cache_ext(), compare with <linux/hdreg.h> */
++#define IDBYTES               512
++#define MASK_EXT      0xE000          /* Bit 15 shall be zero, bit 14 shall 
be one, bit 13 flush cache ext */
++#define TEST_EXT      0x6000
++
++/* Maybe set in list_disks() and used in do_standby_idedisk() */
++#define DISK_IS_IDE   0x00000001
++#define DISK_IS_SATA  0x00000002
++#define DISK_EXTFLUSH 0x00000004
++
++static char *strstrip(char *str);
++static FILE *hdopen(const char* const format, const char* const name);
++static int flush_cache_ext(const char *device);
++
++/*
++ *    Find all disks through /sys/block.
++ */
++static char *list_disks(DIR* blk, unsigned int* flags)
++{
++      struct dirent *d;
++
++      while ((d = readdir(blk))) {
++              *flags = 0;
++              if (d->d_name[1] == 'd' && (d->d_name[0] == 'h' || d->d_name[0] 
== 's')) {
++                      char buf[NAME_MAX+1], lnk[NAME_MAX+1], *ptr;
++                      struct stat st;
++                      FILE *fp;
++                      int ret;
++
++                      fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
++                      if ((long)fp <= 0) {
++                              if ((long)fp < 0)
++                                      goto empty;     /* error */
++                              continue;               /* no entry `removable' 
*/
++                      }
++
++                      ret = getc(fp);
++                      fclose(fp);
++
++                      if (ret != '0')
++                              continue;               /* not a hard disk */
++
++                      if (d->d_name[0] == 'h') {
++                              (*flags) |= DISK_IS_IDE;
++                              if ((ret = flush_cache_ext(d->d_name))) {
++                                      if (ret < 0)
++                                              goto empty;
++                                      (*flags) |= DISK_EXTFLUSH;
++                              }
++                              break;                  /* old IDE disk not 
managed by kernel, out here */
++                      }
++
++                      ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/device", 
d->d_name);
++                      if ((ret >= sizeof(buf)) || (ret < 0))
++                              goto empty;             /* error */
++
++                      ret = readlink(buf, lnk, sizeof(lnk));
++                      if (ret >= sizeof(lnk))
++                              goto empty;             /* error */
++                      if (ret < 0) {
++                              if (errno != ENOENT)
++                                      goto empty;     /* error */
++                              continue;               /* no entry `device' */
++                      }
++                      lnk[ret] = '\0';
++
++                      ptr = basename(lnk);
++                      if (!ptr || !*ptr)
++                              continue;               /* should not happen */
++
++                      ret = snprintf(buf, sizeof(buf), SYS_CLASS 
"/%s/manage_start_stop", ptr);
++                      if ((ret >= sizeof(buf)) || (ret < 0))
++                              goto empty;             /* error */
++
++                      ret = stat(buf, &st);
++                      if (ret == 0)
++                              continue;               /* disk found but 
managed by kernel */
++
++                      if (errno != ENOENT)
++                              goto empty;             /* error */
++
++                      fp = hdopen(SYS_BLK "/%s/device/vendor", d->d_name);
++                      if ((long)fp <= 0) {
++                              if ((long)fp < 0)
++                                      goto empty;     /* error */
++                              continue;               /* no entry 
`device/vendor' */
++                      }
++
++                      ptr = fgets(buf, sizeof(buf), fp);
++                      fclose(fp);
++                      if (ptr == (char*)0)
++                              continue;               /* should not happen */
++
++                      ptr = strstrip(buf);
++                      if (*ptr == '\0')
++                              continue;               /* should not happen */
++
++                      if (strncmp(buf, "ATA", sizeof(buf)))
++                              continue;               /* no SATA but a real 
SCSI disk */
++
++                      (*flags) |= (DISK_IS_IDE|DISK_IS_SATA);
++                      if ((ret = flush_cache_ext(d->d_name))) {
++                              if (ret < 0)
++                                      goto empty;
++                              (*flags) |= DISK_EXTFLUSH;
++                      }
++                      break;                          /* new SATA disk to 
shutdown, out here */
++              }
++      }
++      if (d == (struct dirent*)0)
++              goto empty;
++      return d->d_name;
++empty:
++      return (char*)0;
++}
++
++/*
++ *    Put an disk in standby mode.
++ *    Code stolen from hdparm.c
++ */
++static int do_standby_idedisk(char *device, unsigned int flags)
++{
++#ifndef WIN_STANDBYNOW1
++#define WIN_STANDBYNOW1               0xE0
++#endif
++#ifndef WIN_STANDBYNOW2
++#define WIN_STANDBYNOW2               0x94
++#endif
++#ifndef WIN_FLUSH_CACHE_EXT
++#define WIN_FLUSH_CACHE_EXT   0xEA
++#endif
++#ifndef WIN_FLUSH_CACHE
++#define WIN_FLUSH_CACHE               0xE7
++#endif
++      unsigned char flush1[4] = {WIN_FLUSH_CACHE_EXT,0,0,0};
++      unsigned char flush2[4] = {WIN_FLUSH_CACHE,0,0,0};
++      unsigned char stdby1[4] = {WIN_STANDBYNOW1,0,0,0};
++      unsigned char stdby2[4] = {WIN_STANDBYNOW2,0,0,0};
++      char buf[NAME_MAX+1];
++      int fd, ret;
++
++      ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
++      if ((ret >= sizeof(buf)) || (ret < 0))
++              return -1;
++
++      if ((fd = open(buf, O_RDWR)) < 0)
++              return -1;
++
++      switch (flags & DISK_EXTFLUSH) {
++      case DISK_EXTFLUSH:
++              if (ioctl(fd, HDIO_DRIVE_CMD, &flush1) == 0)
++                      break;
++              /* Extend flush rejected, try standard flush */
++      default:
++              ioctl(fd, HDIO_DRIVE_CMD, &flush2);
++              break;
++      }
++
++      ret = ioctl(fd, HDIO_DRIVE_CMD, &stdby1) &&
++            ioctl(fd, HDIO_DRIVE_CMD, &stdby2);
++      close(fd);
++
++      if (ret)
++              return -1;
++      return 0;
++}
++
++/*
++ *    List all disks and put them in standby mode.
++ *    This has the side-effect of flushing the writecache,
++ *    which is exactly what we want on poweroff.
++ */
++int hddown(void)
++{
++      unsigned int flags;
++      char *disk;
++      DIR *blk;
++
++      if ((blk = opendir(SYS_BLK)) == (DIR*)0)
++              return -1;
++
++      while ((disk = list_disks(blk, &flags)))
++              do_standby_idedisk(disk, flags);
++
++      return closedir(blk);
++}
++
++/*
++ * Strip off trailing white spaces
++ */
++static char *strstrip(char *str)
++{
++      const size_t len = strlen(str);
++      if (len) {
++              char* end = str + len - 1;
++              while ((end != str) && ISSPACE(*end))
++                      end--;
++              *(end + 1) = '\0';                      /* remove trailing 
white spaces */
++      }
++      return str;
++}
++
++/*
++ * Open a sysfs file without getting a controlling tty
++ * and return FILE* pointer.
++ */
++static FILE *hdopen(const char* const format, const char* const name)
++{
++      char buf[NAME_MAX+1];
++      FILE *fp = (FILE*)-1;
++      int fd, ret;
++      
++      ret = snprintf(buf, sizeof(buf), format, name);
++      if ((ret >= sizeof(buf)) || (ret < 0))
++              goto error;             /* error */
++
++      fd = open(buf, O_RDONLY|O_NOCTTY);
++      if (fd < 0) {
++              if (errno != ENOENT)
++                      goto error;     /* error */
++              fp = (FILE*)0;
++              goto error;             /* no entry `removable' */
++      }
++
++      fp = fdopen(fd, "r");
++      if (fp == (FILE*)0)
++              close(fd);              /* should not happen */
++error:
++      return fp;
++}
++
++/*
++ * Check IDE/(S)ATA hard disk identity for
++ * the FLUSH CACHE EXT bit set.
++ */
++static int flush_cache_ext(const char *device)
++{
++#ifndef WIN_IDENTIFY
++#define WIN_IDENTIFY          0xEC
++#endif
++      unsigned char args[4+IDBYTES];
++      unsigned short *id = (unsigned short*)(&args[4]);
++      char buf[NAME_MAX+1], *ptr;
++      int fd = -1, ret = 0;
++      FILE *fp;
++
++      fp = hdopen(SYS_BLK "/%s/size", device);
++      if ((long)fp <= 0) {
++              if ((long)fp < 0)
++                      return -1;      /* error */
++              goto out;               /* no entry `size' */
++      }
++
++      ptr = fgets(buf, sizeof(buf), fp);
++      fclose(fp);
++      if (ptr == (char*)0)
++              goto out;               /* should not happen */
++
++      ptr = strstrip(buf);
++      if (*ptr == '\0')
++              goto out;               /* should not happen */
++
++      if ((size_t)atoll(buf) < (1<<28))
++              goto out;               /* small disk */
++              
++      ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
++      if ((ret >= sizeof(buf)) || (ret < 0))
++              return -1;              /* error */
++
++      if ((fd = open(buf, O_RDONLY|O_NONBLOCK)) < 0)
++              goto out;
++
++      memset(&args[0], 0, sizeof(args));
++      args[0] = WIN_IDENTIFY;
++      args[3] = 1;
++      if (ioctl(fd, HDIO_DRIVE_CMD, &args))
++              goto out;
++#ifdef WORDS_BIGENDIAN
++# if 0
++      {
++              const unsigned short *end = id + IDBYTES/2;
++              const unsigned short *from = id;
++              unsigned short *to = id;
++
++              while (from < end)
++                      *to++ = bswap_16(*from++);
++      }
++# else
++      id[83] = bswap_16(id[83]);
++# endif
++#endif
++      if ((id[83] & MASK_EXT) == TEST_EXT)
++              ret = 1;
++out:
++      if (fd >= 0)
++              close(fd);
++      return ret;
++}
++#else /* ! USE_SYSFS */
+ #define MAX_DISKS     64
+ #define PROC_IDE      "/proc/ide"
+ #define DEV_BASE      "/dev"
+@@ -154,7 +477,7 @@
+ 
+       return (result1 ? result1 : result2);
+ }
+-
++#endif /* ! USE_SYSFS */
+ #else /* __linux__ */
+ 
+ int hddown(void)




-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to