Logo Search packages:      
Sourcecode: hdparm version File versions

hdparm.c

/* hdparm.c - Command line interface to get/set hard disk parameters */
/*          - by Mark Lord (C) 1994-2005 -- freely distributable */
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <endian.h>
#include <sys/ioctl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <linux/types.h>
#include <linux/hdreg.h>
#include <linux/major.h>
#include <asm/byteorder.h>

#include "hdparm.h"

extern const char *minor_str[];

#define VERSION "v6.1"

#undef DO_FLUSHCACHE          /* under construction: force cache flush on -W0 */

#ifndef O_DIRECT
#define O_DIRECT  040000      /* direct disk access, not easily obtained from headers */
#endif

#ifndef CDROM_SELECT_SPEED    /* already defined in 2.3.xx kernels and above */
#define CDROM_SELECT_SPEED    0x5322
#endif

#ifndef BLKGETSIZE64
#define BLKGETSIZE64          _IOR(0x12,114,size_t)
#endif

#define TIMING_BUF_MB         2
#define TIMING_BUF_BYTES      (TIMING_BUF_MB * 1024 * 1024)
#define BUFCACHE_FACTOR       2

char *progname;
static int verbose = 0, get_identity = 0, get_geom = 0, noisy = 1, quiet = 0;
static int flagcount = 0, do_flush = 0;
static int do_ctimings, do_timings = 0;

static unsigned long set_fsreadahead= 0, get_fsreadahead= 0, fsreadahead= 0;
static unsigned long set_readonly = 0, get_readonly = 0, readonly = 0;
static unsigned long set_unmask   = 0, get_unmask   = 0, unmask   = 0;
static unsigned long set_mult     = 0, get_mult     = 0, mult     = 0;
#ifdef HDIO_SET_DMA
static unsigned long set_dma      = 0, get_dma      = 0, dma      = 0;
#endif
#ifdef HDIO_GET_QDMA
static unsigned long set_dma_q        = 0, get_dma_q    = 0, dma_q        = 0;
#endif
#ifdef HDIO_SET_NOWERR
static unsigned long set_nowerr   = 0, get_nowerr   = 0, nowerr   = 0;
#endif
#ifdef HDIO_GET_KEEPSETTINGS
static unsigned long set_keep     = 0, get_keep     = 0, keep     = 0;
#endif
static unsigned long set_io32bit  = 0, get_io32bit  = 0, io32bit  = 0;
#ifdef HDIO_SET_PIO_MODE
static unsigned long set_piomode  = 0, noisy_piomode= 0;
int piomode = 0;
#endif
#ifdef HDIO_DRIVE_CMD
static unsigned long set_dkeep    = 0, get_dkeep    = 0, dkeep    = 0;
static unsigned long set_standby  = 0, get_standby  = 0, standby_requested= 0;
static unsigned long set_xfermode = 0, get_xfermode = 0;
static int xfermode_requested= 0;
static unsigned long set_lookahead= 0, get_lookahead= 0, lookahead= 0;
static unsigned long set_prefetch = 0, get_prefetch = 0, prefetch = 0;
static unsigned long set_defects  = 0, get_defects  = 0, defects  = 0;
static unsigned long set_wcache   = 0, get_wcache   = 0, wcache   = 0;
static unsigned long set_doorlock = 0, get_doorlock = 0, doorlock = 0;
static unsigned long set_seagate  = 0, get_seagate  = 0;
static unsigned long set_standbynow = 0, get_standbynow = 0;
static unsigned long set_sleepnow   = 0, get_sleepnow   = 0;
static unsigned long set_freeze   = 0;
static unsigned long security_master=0, security_mode=0;
static unsigned long set_security   = 0;

#ifndef WIN_SECURITY_FREEZE_LOCK
      #define WIN_SECURITY_SET_PASS       0xF1
      #define WIN_SECURITY_UNLOCK         0xF2
      #define WIN_SECURITY_ERASE_PREPARE  0xF3
      #define WIN_SECURITY_ERASE_UNIT           0xF4
      #define WIN_SECURITY_FREEZE_LOCK    0xF5
      #define WIN_SECURITY_DISABLE        0xF6
#endif
static unsigned int security_command = WIN_SECURITY_UNLOCK;

static char security_password[64];
static unsigned long get_powermode  = 0;
static unsigned long set_apmmode = 0, get_apmmode= 0, apmmode = 0;
#endif
#ifdef CDROM_SELECT_SPEED
static unsigned long set_cdromspeed = 0, cdromspeed = 0;
#endif /* CDROM_SELECT_SPEED */
static int get_IDentity = 0;
#ifdef HDIO_UNREGISTER_HWIF
static int  unregister_hwif = 0;
static int  hwif = 0;
#endif
#ifdef HDIO_SCAN_HWIF
static int  scan_hwif = 0;
static int  hwif_data = 0;
static int  hwif_ctrl = 0;
static int  hwif_irq = 0;
#endif
#ifdef HDIO_GET_BUSSTATE
static int  set_busstate = 0, get_busstate = 0, busstate = 0;
#endif
static int  reread_partn = 0;
#ifdef HDIO_GET_ACOUSTIC
static int  set_acoustic = 0, get_acoustic = 0, acoustic = 0;
#endif

#ifdef HDIO_DRIVE_RESET
static int  perform_reset = 0;
#endif /* HDIO_DRIVE_RESET */
#ifdef HDIO_TRISTATE_HWIF
static int  perform_tristate = 0,   tristate = 0;
#endif /* HDIO_TRISTATE_HWIF */

static int open_flags = O_RDONLY|O_NONBLOCK;

// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
// then the HDIO_GET_IDENTITY only returned 142 bytes.
// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
// and HDIO_GET_IDENTITY returns 512 bytes.  But the latest
// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
// (which they should, but they should just return -EINVAL).
//
// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
// On a really old system, it will not, and we will be confused.
// Too bad, really.

const char *cfg_str[] =
{     "",           " HardSect",   " SoftSect",  " NotMFM",
      " HdSw>15uSec", " SpinMotCtl", " Fixed",     " Removeable",
      " DTR<=5Mbs",   " DTR>5Mbs",   " DTR>10Mbs", " RotSpdTol>.5%",
      " dStbOff",     " TrkOff",     " FmtGapReq", " nonMagnetic"
};

const char *SlowMedFast[]     = {"slow", "medium", "fast", "eide", "ata"};
const char *BuffType[]  = {"unknown", "1Sect", "DualPort", "DualPortCache"};

#define YN(b)     (((b)==0)?"no":"yes")

static void dmpstr (const char *prefix, unsigned int i, const char *s[], unsigned int maxi)
{
      if (i > maxi)
            printf("%s%u", prefix, i);
      else
            printf("%s%s", prefix, s[i]);
}

static void dump_identity (const struct hd_driveid *id)
{
      int i;
      char pmodes[64] = {0,}, dmodes[128]={0,}, umodes[128]={0,};
      const unsigned short int *id_regs= (const void*) id;
      unsigned long capacity;

      printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s",
            id->model, id->fw_rev, id->serial_no);
      printf("\n Config={");
      for (i=0; i<=15; i++) {
            if (id->config & (1<<i))
                  printf("%s", cfg_str[i]);
      }
      printf(" }\n");
      printf(" RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n",
            id->cyls, id->heads, id->sectors,
            id->track_bytes, id->sector_bytes, id->ecc_bytes);
      dmpstr(" BuffType=",id->buf_type,BuffType,3);
      printf(", BuffSize=%ukB, MaxMultSect=%u", id->buf_size/2, id->max_multsect);
      if (id->max_multsect) {
            printf(", MultSect=");
            if (!(id->multsect_valid&1))
                  printf("?%u?", id->multsect);
            else if (id->multsect)
                  printf("%u", id->multsect);
            else
                  printf("off");
      }
      putchar('\n');
      if (id->tPIO <= 5) {
            strcat(pmodes, "pio0 ");
            if (id->tPIO >= 1) strcat(pmodes, "pio1 ");
            if (id->tPIO >= 2) strcat(pmodes, "pio2 ");
      }
      if (!(id->field_valid&1))
            printf(" (maybe):");
      capacity = (id->cur_capacity1 << 16) | id->cur_capacity0;
      printf(" CurCHS=%u/%u/%u, CurSects=%lu", id->cur_cyls, id->cur_heads, id->cur_sectors, capacity);
      printf(", LBA=%s", YN(id->capability&2));
      if (id->capability&2)
            printf(", LBAsects=%u", id->lba_capacity);

      if (id->capability&1) {
            if (id->dma_1word | id->dma_mword) {
                  if (id->dma_1word & 0x100)    strcat(dmodes,"*");
                  if (id->dma_1word & 1)        strcat(dmodes,"sdma0 ");
                  if (id->dma_1word & 0x200)    strcat(dmodes,"*");
                  if (id->dma_1word & 2)        strcat(dmodes,"sdma1 ");
                  if (id->dma_1word & 0x400)    strcat(dmodes,"*");
                  if (id->dma_1word & 4)        strcat(dmodes,"sdma2 ");
                  if (id->dma_1word & 0xf800)   strcat(dmodes,"*");
                  if (id->dma_1word & 0xf8)     strcat(dmodes,"sdma? ");
                  if (id->dma_mword & 0x100)    strcat(dmodes,"*");
                  if (id->dma_mword & 1)        strcat(dmodes,"mdma0 ");
                  if (id->dma_mword & 0x200)    strcat(dmodes,"*");
                  if (id->dma_mword & 2)        strcat(dmodes,"mdma1 ");
                  if (id->dma_mword & 0x400)    strcat(dmodes,"*");
                  if (id->dma_mword & 4)        strcat(dmodes,"mdma2 ");
                  if (id->dma_mword & 0xf800)   strcat(dmodes,"*");
                  if (id->dma_mword & 0xf8)     strcat(dmodes,"mdma? ");
            }
      }
      printf("\n IORDY=");
      if (id->capability&8)
            printf((id->capability&4) ? "on/off" : "yes");
      else
            printf("no");
      if ((id->capability&8) || (id->field_valid&2)) {
            if (id->field_valid&2) {
                  printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
                  if (id->eide_pio_modes & 1)   strcat(pmodes, "pio3 ");
                  if (id->eide_pio_modes & 2)   strcat(pmodes, "pio4 ");
                  if (id->eide_pio_modes &~3)   strcat(pmodes, "pio? ");
            }
            if (id->field_valid&4) {
                  if (id->dma_ultra & 0x100)    strcat(umodes,"*");
                  if (id->dma_ultra & 0x001)    strcat(umodes,"udma0 ");
                  if (id->dma_ultra & 0x200)    strcat(umodes,"*");
                  if (id->dma_ultra & 0x002)    strcat(umodes,"udma1 ");
                  if (id->dma_ultra & 0x400)    strcat(umodes,"*");
                  if (id->dma_ultra & 0x004)    strcat(umodes,"udma2 ");
#ifdef __NEW_HD_DRIVE_ID
                  if (id->hw_config & 0x2000) {
#else /* !__NEW_HD_DRIVE_ID */
                  if (id->word93 & 0x2000) {
#endif /* __NEW_HD_DRIVE_ID */
                        if (id->dma_ultra & 0x0800)   strcat(umodes,"*");
                        if (id->dma_ultra & 0x0008)   strcat(umodes,"udma3 ");
                        if (id->dma_ultra & 0x1000)   strcat(umodes,"*");
                        if (id->dma_ultra & 0x0010)   strcat(umodes,"udma4 ");
                        if (id->dma_ultra & 0x2000)   strcat(umodes,"*");
                        if (id->dma_ultra & 0x0020)   strcat(umodes,"udma5 ");
                        if (id->dma_ultra & 0x4000)   strcat(umodes,"*");
                        if (id->dma_ultra & 0x0040)   strcat(umodes,"udma6 ");
                        if (id->dma_ultra & 0x8000)   strcat(umodes,"*");
                        if (id->dma_ultra & 0x0080)   strcat(umodes,"udma7 ");
                  }
            }
      }
      if ((id->capability&1) && (id->field_valid&2))
            printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
      printf("\n PIO modes:  %s", pmodes);
      if (*dmodes)
            printf("\n DMA modes:  %s", dmodes);
      if (*umodes)
            printf("\n UDMA modes: %s", umodes);

      printf("\n AdvancedPM=%s",YN(id_regs[83]&8));
      if (id_regs[83] & 8) {
            if (!(id_regs[86]&8))
                  printf(": disabled (255)");
            else if ((id_regs[91]&0xFF00)!=0x4000)
                  printf(": unknown setting");
            else
                  printf(": mode=0x%02X (%u)",id_regs[91]&0xFF,id_regs[91]&0xFF);
      }
      if (id_regs[82]&0x20)
            printf(" WriteCache=%s",(id_regs[85]&0x20) ? "enabled" : "disabled");
#ifdef __NEW_HD_DRIVE_ID
      if (id->minor_rev_num || id->major_rev_num) {
            printf("\n Drive conforms to: ");
            if (id->minor_rev_num <= 31)
                  printf("%s: ", minor_str[id->minor_rev_num]);
            else
                  printf("unknown: ");
            if (id->major_rev_num < 31) {
                  for (i=0; i <= 15; i++) {
                        if (id->major_rev_num & (1<<i))
                              printf(" %u", i);
                  }
            }
      }
#endif /* __NEW_HD_DRIVE_ID */
      printf("\n");
      printf("\n * signifies the current active mode\n");
      printf("\n");
}

void flush_buffer_cache (int fd)
{
      fsync (fd);                   /* flush buffers */
      if (ioctl(fd, BLKFLSBUF, NULL))           /* do it again, big time */
            perror("BLKFLSBUF failed");
#ifdef HDIO_DRIVE_CMD
      if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL)     /* await completion */
            perror("HDIO_DRIVE_CMD(null) (wait for flush complete) failed");
#endif
}

int seek_to_zero (int fd)
{
      if (lseek(fd, (off_t) 0, SEEK_SET)) {
            perror("lseek() failed");
            return 1;
      }
      return 0;
}

int read_big_block (int fd, char *buf)
{
      int i, rc;
      if ((rc = read(fd, buf, TIMING_BUF_BYTES)) != TIMING_BUF_BYTES) {
            if (rc) {
                  if (rc == -1)
                        perror("read() failed");
                  else
                        fprintf(stderr, "read(%u) returned %u bytes\n", TIMING_BUF_BYTES, rc);
            } else {
                  fputs ("read() hit EOF - device too small\n", stderr);
            }
            return 1;
      }
      /* access all sectors of buf to ensure the read fully completed */
      for (i = 0; i < TIMING_BUF_BYTES; i += 512)
            buf[i] &= 1;
      return 0;
}

void time_cache (int fd)
{
      char *buf;
      struct itimerval e1, e2;
      int shmid;
      double elapsed, elapsed2;
      unsigned int iterations, total_MB;

      if ((shmid = shmget(IPC_PRIVATE, TIMING_BUF_BYTES, 0600)) == -1) {
            perror ("could not allocate sharedmem buf");
            return;
      }
      if (shmctl(shmid, SHM_LOCK, NULL) == -1) {
            perror ("could not lock sharedmem buf");
            (void) shmctl(shmid, IPC_RMID, NULL);
            return;
      }
      if ((buf = shmat(shmid, (char *) 0, 0)) == (char *) -1) {
            perror ("could not attach sharedmem buf");
            (void) shmctl(shmid, IPC_RMID, NULL);
            return;
      }
      if (shmctl(shmid, IPC_RMID, NULL) == -1)
            perror ("shmctl(,IPC_RMID,) failed");

      /* Clear out the device request queues & give them time to complete */
      sync();
      sleep(3);

      /*
       * getitimer() is used rather than gettimeofday() because
       * it is much more consistent (on my machine, at least).
       */
      setitimer(ITIMER_REAL, &(struct itimerval){{1000,0},{1000,0}}, NULL);
      if (seek_to_zero (fd)) return;
      if (read_big_block (fd, buf)) return;
      printf(" Timing %scached reads:   ", (open_flags & O_DIRECT) ? "O_DIRECT " : "");
      fflush(stdout);

      /* Clear out the device request queues & give them time to complete */
      sync();
      sleep(1);

      /* Now do the timing */
      iterations = 0;
      getitimer(ITIMER_REAL, &e1);
      do {
            ++iterations;
            if (seek_to_zero (fd) || read_big_block (fd, buf))
                  goto quit;
            getitimer(ITIMER_REAL, &e2);
            elapsed = (e1.it_value.tv_sec - e2.it_value.tv_sec)
             + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0);
      } while (elapsed < 2.0);
      total_MB = iterations * TIMING_BUF_MB;

      elapsed = (e1.it_value.tv_sec - e2.it_value.tv_sec)
       + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0);

      /* Now remove the lseek() and getitimer() overheads from the elapsed time */
      getitimer(ITIMER_REAL, &e1);
      do {
            if (seek_to_zero (fd))
                  goto quit;
            getitimer(ITIMER_REAL, &e2);
            elapsed2 = (e1.it_value.tv_sec - e2.it_value.tv_sec)
             + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0);
      } while (--iterations);

      elapsed -= elapsed2;

      if ((BUFCACHE_FACTOR * total_MB) >= elapsed)  /* more than 1MB/s */
            printf("%3u MB in %5.2f seconds = %6.2f MB/sec\n",
                  (BUFCACHE_FACTOR * total_MB), elapsed,
                  (BUFCACHE_FACTOR * total_MB) / elapsed);
      else
            printf("%3u MB in %5.2f seconds = %6.2f kB/sec\n",
                  (BUFCACHE_FACTOR * total_MB), elapsed,
                  (BUFCACHE_FACTOR * total_MB) / elapsed * 1024);

      flush_buffer_cache(fd);
      sleep(1);
quit:
      if (-1 == shmdt(buf))
            perror ("could not detach sharedmem buf");
}

static int do_blkgetsize (int fd, unsigned long long *blksize64)
{
      int         rc;
      unsigned int      blksize32 = 0;

      if (0 == ioctl(fd, BLKGETSIZE64, blksize64)) {  // returns bytes
            *blksize64 /= 512;
            return 0;
      }
      rc = ioctl(fd, BLKGETSIZE, &blksize32);   // returns sectors
      if (rc)
            perror(" BLKGETSIZE failed");
      *blksize64 = blksize32;
      return rc;
}

void time_device (int fd)
{
      char *buf;
      double elapsed;
      struct itimerval e1, e2;
      int shmid;
      unsigned int max_iterations = 1024, total_MB, iterations;

      //
      // get device size
      //
      if (do_ctimings || do_timings) {
            unsigned long long blksize;
            if (0 == do_blkgetsize(fd, &blksize))
                  max_iterations = blksize / (2 * 1024) / TIMING_BUF_MB;
      }

      if ((shmid = shmget(IPC_PRIVATE, TIMING_BUF_BYTES, 0600)) == -1) {
            perror ("could not allocate sharedmem buf");
            return;
      }
      if (shmctl(shmid, SHM_LOCK, NULL) == -1) {
            perror ("could not lock sharedmem buf");
            (void) shmctl(shmid, IPC_RMID, NULL);
            return;
      }
      if ((buf = shmat(shmid, (char *) 0, 0)) == (char *) -1) {
            perror ("could not attach sharedmem buf");
            (void) shmctl(shmid, IPC_RMID, NULL);
            return;
      }
      if (shmctl(shmid, IPC_RMID, NULL) == -1)
            perror ("shmctl(,IPC_RMID,) failed");

      /* Clear out the device request queues & give them time to complete */
      sync();
      sleep(3);

      printf(" Timing %s disk reads:  ", (open_flags & O_DIRECT) ? "O_DIRECT" : "buffered");
      fflush(stdout);

      /*
       * getitimer() is used rather than gettimeofday() because
       * it is much more consistent (on my machine, at least).
       */
      setitimer(ITIMER_REAL, &(struct itimerval){{1000,0},{1000,0}}, NULL);

      /* Now do the timings for real */
      iterations = 0;
      getitimer(ITIMER_REAL, &e1);
      do {
            ++iterations;
            if (read_big_block (fd, buf))
                  goto quit;
            getitimer(ITIMER_REAL, &e2);
            elapsed = (e1.it_value.tv_sec - e2.it_value.tv_sec)
             + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0);
      } while (elapsed < 3.0 && iterations < max_iterations);

      total_MB = iterations * TIMING_BUF_MB;
      if ((total_MB / elapsed) > 1.0)  /* more than 1MB/s */
            printf("%3u MB in %5.2f seconds = %6.2f MB/sec\n",
                  total_MB, elapsed, total_MB / elapsed);
      else
            printf("%3u MB in %5.2f seconds = %6.2f kB/sec\n",
                  total_MB, elapsed, total_MB / elapsed * 1024);
quit:
      if (-1 == shmdt(buf))
            perror ("could not detach sharedmem buf");
}

static void on_off (unsigned int value)
{
      printf(value ? " (on)\n" : " (off)\n");
}

#ifdef HDIO_GET_BUSSTATE
static void bus_state_value (unsigned int value)
{
      const char *string;

      switch (value) {
      case BUSSTATE_ON:
            string = " (on)\n";
            break;
      case BUSSTATE_OFF:
            string = " (off)\n";
            break;
      case BUSSTATE_TRISTATE:
            string = " (tristate)\n";
            break;
      default:
            string = " (unknown: %d)\n";
            break;
      }
      printf(string, value);
}
#endif

#ifdef HDIO_DRIVE_CMD
static void interpret_standby (unsigned int standby)
{
      printf(" (");
      switch(standby) {
            case 0:           printf("off");
                        break;
            case 252:   printf("21 minutes");
                        break;
            case 253:   printf("vendor-specific");
                        break;
            case 254:   printf("?reserved");
                        break;
            case 255:   printf("21 minutes + 15 seconds");
                        break;
            default:
                  if (standby <= 240) {
                        unsigned int secs = standby * 5;
                        unsigned int mins = secs / 60;
                        secs %= 60;
                        if (mins)     printf("%u minutes", mins);
                        if (mins && secs) printf(" + ");
                        if (secs)     printf("%u seconds", secs);
                  } else if (standby <= 251) {
                        unsigned int mins = (standby - 240) * 30;
                        unsigned int hrs  = mins / 60;
                        mins %= 60;
                        if (hrs)      printf("%u hours", hrs);
                        if (hrs && mins)  printf(" + ");
                        if (mins)     printf("%u minutes", mins);
                  } else
                        printf("illegal value");
                  break;
      }
      printf(")\n");
}

struct xfermode_entry {
      int val;
      const char *name;
};

static const struct xfermode_entry xfermode_table[] = {
      { 8,    "pio0" },
      { 9,    "pio1" },
      { 10,   "pio2" },
      { 11,   "pio3" },
      { 12,   "pio4" },
      { 13,   "pio5" },
      { 14,   "pio6" },
      { 15,   "pio7" },
      { 16,   "sdma0" },
      { 17,   "sdma1" },
      { 18,   "sdma2" },
      { 19,   "sdma3" },
      { 20,   "sdma4" },
      { 21,   "sdma5" },
      { 22,   "sdma6" },
      { 23,   "sdma7" },
      { 32,   "mdma0" },
      { 33,   "mdma1" },
      { 34,   "mdma2" },
      { 35,   "mdma3" },
      { 36,   "mdma4" },
      { 37,   "mdma5" },
      { 38,   "mdma6" },
      { 39,   "mdma7" },
      { 64,   "udma0" },
      { 65,   "udma1" },
      { 66,   "udma2" },
      { 67,   "udma3" },
      { 68,   "udma4" },
      { 69,   "udma5" },
      { 70,   "udma6" },
      { 71,   "udma7" },
      { 0, NULL }
};

static int translate_xfermode(char * name)
{
      const struct xfermode_entry *tmp;
      char *endptr;
      int val = -1;

      for (tmp = xfermode_table; tmp->name != NULL; ++tmp) {
            if (!strcmp(name, tmp->name))
                  return tmp->val;
      }
      val = strtol(name, &endptr, 10);
      if (*endptr == '\0')
            return val;
      return -1;
}

static void interpret_xfermode (unsigned int xfermode)
{
      printf(" (");
      switch(xfermode) {
            case 0:           printf("default PIO mode");
                        break;
            case 1:           printf("default PIO mode, disable IORDY");
                        break;
            case 8:
            case 9:
            case 10:
            case 11:
            case 12:
            case 13:
            case 14:
            case 15:    printf("PIO flow control mode%u", xfermode-8);
                        break;
            case 16:
            case 17:
            case 18:
            case 19:
            case 20:
            case 21:
            case 22:
            case 23:    printf("singleword DMA mode%u", xfermode-16);
                        break;
            case 32:
            case 33:
            case 34:
            case 35:
            case 36:
            case 37:
            case 38:
            case 39:    printf("multiword DMA mode%u", xfermode-32);
                        break;
            case 64:
            case 65:
            case 66:
            case 67:
            case 68:
            case 69:
            case 70:
            case 71:    printf("UltraDMA mode%u", xfermode-64);
                        break;
            default:
                        printf("unknown, probably not valid");
                        break;
      }
      printf(")\n");
}
#endif /* HDIO_DRIVE_CMD */

#ifndef VXVM_MAJOR
#define VXVM_MAJOR 199
#endif

#ifndef CCISS_MAJOR
#define CCISS_MAJOR 104
#endif

void process_dev (char *devname)
{
      int fd;
      static long parm, multcount;
#ifndef HDIO_DRIVE_CMD
      int force_operation = 0;
#endif

      fd = open (devname, open_flags);
      if (fd < 0) {
            perror(devname);
            exit(errno);
      }
      if (!quiet)
            printf("\n%s:\n", devname);

      if (set_fsreadahead) {
            if (get_fsreadahead)
                  printf(" setting fs readahead to %ld\n", fsreadahead);
            if (ioctl(fd, BLKRASET, fsreadahead))
                  perror(" BLKRASET failed");
      }
#ifdef HDIO_UNREGISTER_HWIF
      if (unregister_hwif) {
            printf(" attempting to unregister hwif#%u\n", hwif);
            if (ioctl(fd, HDIO_UNREGISTER_HWIF, hwif))
                  perror(" HDIO_UNREGISTER_HWIF failed");
      }
#endif
#ifdef HDIO_SCAN_HWIF
      if (scan_hwif) {
            int   args[3];
            printf(" attempting to scan hwif (0x%x, 0x%x, %u)\n", hwif_data, hwif_ctrl, hwif_irq);
            args[0] = hwif_data;
            args[1] = hwif_ctrl;
            args[2] = hwif_irq;
            if (ioctl(fd, HDIO_SCAN_HWIF, args))
                  perror(" HDIO_SCAN_HWIF failed");
      }
#endif
#ifdef HDIO_SET_PIO_MODE
      if (set_piomode) {
            if (noisy_piomode) {
                  if (piomode == 255)
                        printf(" attempting to auto-tune PIO mode\n");
                  else if (piomode < 100)
                        printf(" attempting to set PIO mode to %d\n", piomode);
                  else if (piomode < 200)
                        printf(" attempting to set MDMA mode to %d\n", (piomode-100));
                  else
                        printf(" attempting to set UDMA mode to %d\n", (piomode-200));
            }
            if (ioctl(fd, HDIO_SET_PIO_MODE, piomode))
                  perror(" HDIO_SET_PIO_MODE failed");
      }
#endif
      if (set_io32bit) {
            if (get_io32bit)
                  printf(" setting 32-bit IO_support flag to %ld\n", io32bit);
            if (ioctl(fd, HDIO_SET_32BIT, io32bit))
                  perror(" HDIO_SET_32BIT failed");
      }
      if (set_mult) {
            if (get_mult)
                  printf(" setting multcount to %ld\n", mult);
            if (ioctl(fd, HDIO_SET_MULTCOUNT, mult))
                  perror(" HDIO_SET_MULTCOUNT failed");
#ifndef HDIO_DRIVE_CMD
            else force_operation = 1;
#endif
      }
      if (set_readonly) {
            if (get_readonly) {
                  printf(" setting readonly to %ld", readonly);
                  on_off(readonly);
            }
            if (ioctl(fd, BLKROSET, &readonly))
                  perror(" BLKROSET failed");
      }
      if (set_unmask) {
            if (get_unmask) {
                  printf(" setting unmaskirq to %ld", unmask);
                  on_off(unmask);
            }
            if (ioctl(fd, HDIO_SET_UNMASKINTR, unmask))
                  perror(" HDIO_SET_UNMASKINTR failed");
      }
#ifdef HDIO_SET_DMA
      if (set_dma) {
            if (get_dma) {
                  printf(" setting using_dma to %ld", dma);
                  on_off(dma);
            }
            if (ioctl(fd, HDIO_SET_DMA, dma))
                  perror(" HDIO_SET_DMA failed");
      }
#endif
#ifdef HDIO_SET_QDMA
      if (set_dma_q) {
            if (get_dma_q) {
                  printf(" setting DMA queue_depth to %ld", dma_q);
                  on_off(dma_q);
            }
            if (ioctl(fd, HDIO_SET_QDMA, dma_q))
                  perror(" HDIO_SET_QDMA failed");
      }
#endif
#ifdef HDIO_SET_NOWERR
      if (set_nowerr) {
            if (get_nowerr) {
                  printf(" setting nowerr to %ld", nowerr);
                  on_off(nowerr);
            }
            if (ioctl(fd, HDIO_SET_NOWERR, nowerr))
                  perror(" HDIO_SET_NOWERR failed");
      }
#endif
#ifdef HDIO_GET_KEEPSETTINGS
      if (set_keep) {
            if (get_keep) {
                  printf(" setting keep_settings to %ld", keep);
                  on_off(keep);
            }
            if (ioctl(fd, HDIO_SET_KEEPSETTINGS, keep))
                  perror(" HDIO_SET_KEEPSETTINGS failed");
      }
#endif /* HDIO_GET_KEEPSETTINGS */
#ifdef HDIO_DRIVE_CMD
      if (set_doorlock) {
            unsigned char args[4] = {0,0,0,0};
            args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
            if (get_doorlock) {
                  printf(" setting drive doorlock to %ld", doorlock);
                  on_off(doorlock);
            }
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(doorlock) failed");
      }
      if (set_dkeep) {
            /* lock/unlock the drive's "feature" settings */
            unsigned char args[4] = {WIN_SETFEATURES,0,0,0};
            if (get_dkeep) {
                  printf(" setting drive keep features to %ld", dkeep);
                  on_off(dkeep);
            }
            args[2] = dkeep ? 0x66 : 0xcc;
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(keepsettings) failed");
      }
      if (set_defects) {
            unsigned char args[4] = {WIN_SETFEATURES,0,0x04,0};
            args[2] = defects ? 0x04 : 0x84;
            if (get_defects)
                  printf(" setting drive defect management to %ld\n", defects);
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(defectmgmt) failed");
      }
      if (set_prefetch) {
            unsigned char args[4] = {WIN_SETFEATURES,0,0xab,0};
            args[1] = prefetch;
            if (get_prefetch)
                  printf(" setting drive prefetch to %ld\n", prefetch);
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(setprefetch) failed");
      }
      if (set_xfermode) {
            unsigned char args[4] = {WIN_SETFEATURES,0,3,0};
            args[1] = xfermode_requested;
            if (get_xfermode) {
                  printf(" setting xfermode to %d", xfermode_requested);
                  interpret_xfermode(xfermode_requested);
            }
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(setxfermode) failed");
      }
      if (set_lookahead) {
            unsigned char args[4] = {WIN_SETFEATURES,0,0,0};
            args[2] = lookahead ? 0xaa : 0x55;
            if (get_lookahead) {
                  printf(" setting drive read-lookahead to %ld", lookahead);
                  on_off(lookahead);
            }
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(setreadahead) failed");
      }
      if (set_apmmode) {
            unsigned char args[4] = {WIN_SETFEATURES,0,0,0};
            if (apmmode<1) apmmode=1;
            if (apmmode>255) apmmode=255;
            if (get_apmmode)
                  printf(" setting Advanced Power Management level to");
            if (apmmode==255) {
                  /* disable Advanced Power Management */
                  args[2] = 0x85; /* feature register */
                  if (get_apmmode) printf(" disabled\n");
            } else {
                  /* set Advanced Power Management mode */
                  args[2] = 0x05; /* feature register */
                  args[1] = apmmode; /* sector count register */
                  if (get_apmmode) printf(" 0x%02lX (%ld)\n",apmmode,apmmode);
            }
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD failed");
      }
#ifdef CDROM_SELECT_SPEED
      if (set_cdromspeed) {
            printf ("setting cdrom speed to %ld\n", cdromspeed);
            if (ioctl (fd, CDROM_SELECT_SPEED, cdromspeed))
                  perror(" CDROM_SELECT_SPEED failed");
      }
#endif
      if (set_wcache) {
#ifdef DO_FLUSHCACHE
#ifndef WIN_FLUSHCACHE
#define WIN_FLUSHCACHE 0xe7
#endif
            unsigned char flushcache[4] = {WIN_FLUSHCACHE,0,0,0};
#endif /* DO_FLUSHCACHE */
            unsigned char args[4] = {WIN_SETFEATURES,0,0,0};
            args[2] = wcache ? 0x02 : 0x82;
            if (get_wcache) {
                  printf(" setting drive write-caching to %ld", wcache);
                  on_off(wcache);
            }
#ifdef HDIO_SET_WCACHE
            if (ioctl(fd, HDIO_SET_WCACHE, wcache))
#endif
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(setcache) failed");
#ifdef DO_FLUSHCACHE
            if (!wcache && ioctl(fd, HDIO_DRIVE_CMD, &flushcache))
                  perror (" HDIO_DRIVE_CMD(flushcache) failed");
#endif /* DO_FLUSHCACHE */
      }
      if (set_standbynow) {
#ifndef WIN_STANDBYNOW1
#define WIN_STANDBYNOW1 0xE0
#endif
#ifndef WIN_STANDBYNOW2
#define WIN_STANDBYNOW2 0x94
#endif
            unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
            unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
            if (get_standbynow)
                  printf(" issuing standby command\n");
            if (ioctl(fd, HDIO_DRIVE_CMD, &args1)
             && ioctl(fd, HDIO_DRIVE_CMD, &args2))
                  perror(" HDIO_DRIVE_CMD(standby) failed");
      }
      if (set_sleepnow) {
#ifndef WIN_SLEEPNOW1
#define WIN_SLEEPNOW1 0xE6
#endif
#ifndef WIN_SLEEPNOW2
#define WIN_SLEEPNOW2 0x99
#endif
            unsigned char args1[4] = {WIN_SLEEPNOW1,0,0,0};
            unsigned char args2[4] = {WIN_SLEEPNOW2,0,0,0};
            if (get_sleepnow)
                  printf(" issuing sleep command\n");
            if (ioctl(fd, HDIO_DRIVE_CMD, &args1)
             && ioctl(fd, HDIO_DRIVE_CMD, &args2))
                  perror(" HDIO_DRIVE_CMD(sleep) failed");
      }
#ifdef WIN_SECURITY_UNLOCK
      if (set_security) {
#ifndef TASKFILE_OUT
#define TASKFILE_OUT 4
#endif
#ifndef HDIO_DRIVE_TASKFILE
#define HDIO_DRIVE_TASKFILE 0x031d
#endif
            const char *description;
            struct request {
                  unsigned char     regs[16];
                  unsigned int      flags;
                  unsigned int      phase;
                  unsigned int      cmd;
                  unsigned long     obytes;
                  unsigned long     ibytes;
                  unsigned char     data[512];
            } request;

            memset(&request, 0, sizeof(request));
            request.regs[7]   = security_command;
            request.phase     = TASKFILE_OUT;
            request.cmd = IDE_DRIVE_TASK_OUT;
            request.obytes    = 512;
            request.data[0]   = (security_master & 0x01);
            request.data[1]   = (security_mode   & 0x01) << 8;

            // Copy the password into the data section
            memcpy(&request.data[2], security_password, 32);

            switch (security_command) {
                  case WIN_SECURITY_UNLOCK:
                        description = "SECURITY_UNLOCK";
                        break;
                  case WIN_SECURITY_SET_PASS:
                        description = "SECURITY_SET_PASS";
                        break;
                  case WIN_SECURITY_DISABLE:
                        description = "SECURITY_DISABLE";
                        break;
                  default:
                        description = "NOTHING";
            }
            printf(" Issuing %s command, mode=%u/%u, password=\"%s\"\n",
                  description, request.data[1], request.data[0], request.data + 2);
            if (ioctl(fd,HDIO_DRIVE_TASKFILE,&request))
                  perror("Problem issuing security command");
      }
#endif
#ifdef WIN_SECURITY_FREEZE_LOCK
      if (set_freeze) {
            unsigned char args[4] = {WIN_SECURITY_FREEZE_LOCK,0,0,0};
            printf(" issuing Security Freeze command\n");
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(freeze) failed");
      }
#endif
      if (set_seagate) {
            unsigned char args[4] = {0xfb,0,0,0};
            if (get_seagate)
                  printf(" disabling Seagate auto powersaving mode\n");
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(seagatepwrsave) failed");
      }
      if (set_standby) {
            unsigned char args[4] = {WIN_SETIDLE1,standby_requested,0,0};
            if (get_standby) {
                  printf(" setting standby to %lu", standby_requested);
                  interpret_standby(standby_requested);
            }
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD(setidle1) failed");
      }
#else /* HDIO_DRIVE_CMD */
      if (force_operation) {
            char buf[512];
            flush_buffer_cache(fd);
            if (-1 == read(fd, buf, sizeof(buf)))
                  perror(" access failed");
      }
#endif      /* HDIO_DRIVE_CMD */

      if (!flagcount)
            verbose = 1;

      if (verbose || get_mult || get_identity) {
            multcount = -1;
            if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
                  if (get_mult)
                        perror(" HDIO_GET_MULTCOUNT failed");
            } else if (verbose | get_mult) {
                  printf(" multcount    = %2ld", multcount);
                  on_off(multcount);
            }
      }
      if (verbose || get_io32bit) {
            if (0 == ioctl(fd, HDIO_GET_32BIT, &parm)) {
                  printf(" IO_support   =%3ld (", parm);
                  switch (parm) {
                        case 0:     printf("default ");
                        case 2: printf("16-bit)\n");
                              break;
                        case 1:     printf("32-bit)\n");
                              break;
                        case 3:     printf("32-bit w/sync)\n");
                              break;
                        case 8:     printf("Request-Queue-Bypass)\n");
                              break;
                        default:printf("\?\?\?)\n");
                  }
            }
      }
      if (verbose || get_unmask) {
            if (0 == ioctl(fd, HDIO_GET_UNMASKINTR, &parm)) {
                  printf(" unmaskirq    = %2ld", parm);
                  on_off(parm);
            }
      }

#ifdef HDIO_GET_DMA
      if (verbose || get_dma) {
            if (0 == ioctl(fd, HDIO_GET_DMA, &parm)) {
                  printf(" using_dma    = %2ld", parm);
                  if (parm == 8)
                        printf(" (DMA-Assisted-PIO)\n");
                  else
                        on_off(parm);
            }
      }
#endif
#ifdef HDIO_GET_QDMA
      if (get_dma_q) {
            if(ioctl(fd, HDIO_GET_QDMA, &parm)) {
                  perror(" HDIO_GET_QDMA failed");
            } else {
                  printf(" queue_depth  = %2ld", parm);
                  on_off(parm);
            }
      }
#endif
#ifdef HDIO_GET_KEEPSETTINGS
      if (verbose || get_keep) {
            if (0 == ioctl(fd, HDIO_GET_KEEPSETTINGS, &parm)) {
                  printf(" keepsettings = %2ld", parm);
                  on_off(parm);
            }
      }
#endif /* HDIO_GET_KEEPSETTINGS */

#ifdef HDIO_SET_NOWERR
      if (get_nowerr) {
            if (ioctl(fd, HDIO_GET_NOWERR, &parm))
                  perror(" HDIO_GET_NOWERR failed");
            else {
                  printf(" nowerr       = %2ld", parm);
                  on_off(parm);
            }
      }
#endif
      if (verbose || get_readonly) {
            if (ioctl(fd, BLKROGET, &parm))
                  perror(" BLKROGET failed");
            else {
                  printf(" readonly     = %2ld", parm);
                  on_off(parm);
            }
      }
      if (verbose || get_fsreadahead) {
            if (ioctl(fd, BLKRAGET, &parm))
                  perror(" BLKRAGET failed");
            else {
                  printf(" readahead    = %2ld", parm);
                  on_off(parm);
            }
      }
      if (verbose || get_geom) {
            unsigned long long blksize;
            static const char msg[] = " geometry     = %u/%u/%u, sectors = %lld, start = %ld\n";
// Note to self:  when compiled 32-bit (AMD,Mips64), the userspace version of this struct
// is going to be 32-bits smaller than the kernel representation.. random stack corruption!
            static struct hd_geometry g;
#ifdef HDIO_GETGEO_BIG
            static struct hd_big_geometry bg;
#endif

            if (0 == do_blkgetsize(fd, &blksize)) {
#ifdef HDIO_GETGEO_BIG
                  if (!ioctl(fd, HDIO_GETGEO_BIG, &bg))
                        printf(msg, bg.cylinders, bg.heads, bg.sectors, blksize, bg.start);
                  else
#endif
                  if (ioctl(fd, HDIO_GETGEO, &g))
                        perror(" HDIO_GETGEO failed");
                  else
                        printf(msg, g.cylinders, g.heads, g.sectors, blksize, g.start);
            }
      }
#ifdef HDIO_DRIVE_CMD
      if (get_powermode) {
#ifndef WIN_CHECKPOWERMODE1
#define WIN_CHECKPOWERMODE1 0xE5
#endif
#ifndef WIN_CHECKPOWERMODE2
#define WIN_CHECKPOWERMODE2 0x98
#endif
            unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
            const char *state;
            if (ioctl(fd, HDIO_DRIVE_CMD, &args)
             && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
             && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
                  if (errno != EIO || args[0] != 0 || args[1] != 0)
                        state = "unknown";
                  else
                        state = "sleeping";
            } else {
                  state = (args[2] == 255) ? "active/idle" : "standby";
            }
            printf(" drive state is:  %s\n", state);
      }
#endif
#ifdef HDIO_DRIVE_RESET
      if (perform_reset) {
            if (ioctl(fd, HDIO_DRIVE_RESET, NULL))
                  perror(" HDIO_DRIVE_RESET failed");
      }
#endif /* HDIO_DRIVE_RESET */
#ifdef HDIO_TRISTATE_HWIF
      if (perform_tristate) {
            unsigned char args[4] = {0,tristate,0,0};
            if (ioctl(fd, HDIO_TRISTATE_HWIF, &args))
                  perror(" HDIO_TRISTATE_HWIF failed");
      }
#endif /* HDIO_TRISTATE_HWIF */
      if (get_identity) {
            static struct hd_driveid id;

            if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
                  if (multcount != -1) {
                        id.multsect = multcount;
                        id.multsect_valid |= 1;
                  } else
                        id.multsect_valid &= ~1;
                  dump_identity(&id);
            } else if (errno == -ENOMSG)
                  printf(" no identification info available\n");
            else
                  perror(" HDIO_GET_IDENTITY failed");
      }
      if (get_IDentity) {
            __u16 *id;
            unsigned char args[4+512] = {WIN_IDENTIFY,0,0,1,};
            unsigned i;
            if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
                  args[0] = WIN_PIDENTIFY;
                  if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
                        perror(" HDIO_DRIVE_CMD(identify) failed");
                        goto identify_abort;
                  }
            }
            id = (__u16 *)&args[4];
            if (get_IDentity == 2) {
                  for (i = 0; i < (256/8); ++i) {
                        printf("%04x %04x %04x %04x %04x %04x %04x %04x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
                        id += 8;
                  }
            } else {
                  for(i = 0; i < 0x100; ++i) {
                        __le16_to_cpus(&id[i]);
                  }
                  identify((void *)id, NULL);
            }
identify_abort:   ;
      }
#ifdef HDIO_SET_BUSSTATE
      if (set_busstate) {
            if (get_busstate) {
                  printf(" setting bus state to %d", busstate);
                  bus_state_value(busstate);
            }
            if (ioctl(fd, HDIO_SET_BUSSTATE, busstate))
                  perror(" HDIO_SET_BUSSTATE failed");
      }
#endif
#ifdef HDIO_GET_BUSSTATE
      if (get_busstate) {
            if (ioctl(fd, HDIO_GET_BUSSTATE, &parm))
                  perror(" HDIO_GET_BUSSTATE failed");
            else {
                  printf(" busstate     = %2ld", parm);
                  bus_state_value(parm);
            }
      }
#endif
      if (reread_partn) {
            if (ioctl(fd, BLKRRPART, NULL)) {
                  perror(" BLKRRPART failed");
            }
      }
 #ifdef HDIO_SET_ACOUSTIC
      if (set_acoustic) {
            if (get_acoustic) {
                  printf(" setting acoustic management to %d\n", acoustic);
            }
#if 0
            if (ioctl(fd, HDIO_SET_ACOUSTIC, acoustic))
                  perror(" HDIO_SET_ACOUSTIC failed");
#else
{
            unsigned char args[4] = {WIN_SETFEATURES,0,0,0};
            args[1] = acoustic;
            args[2] = acoustic ? 0x42 : 0xc2;
            if (ioctl(fd, HDIO_DRIVE_CMD, &args))
                  perror(" HDIO_DRIVE_CMD:ACOUSTIC failed");
}
#endif
      }
 #endif /* HDIO_SET_ACOUSTIC */
 #ifdef HDIO_GET_ACOUSTIC
      if (get_acoustic) {
            if (ioctl(fd, HDIO_GET_ACOUSTIC, &parm)) {
                  perror(" HDIO_GET_ACOUSTIC failed");
            } else {
                  printf(" acoustic     = %2ld (128=quiet ... 254=fast)\n", parm);
            }
      }
 #endif /* HDIO_GET_ACOUSTIC */

      if (do_ctimings)
            time_cache (fd);
      if (do_timings)
            time_device (fd);
      if (do_flush)
            flush_buffer_cache (fd);
      close (fd);
}

void usage_error (int out)
{
      FILE *desc;
      int ret;

      if (out == 0) {
            desc = stdout;
            ret = 0;
      } else {
            desc = stderr;
            ret = 1;
      }

      fprintf(desc,"\n%s - get/set hard disk parameters - version %s\n\n", progname, VERSION);
      fprintf(desc,"Usage:  %s  [options] [device] ..\n\n", progname);
      fprintf(desc,"Options:\n"
      " -a   get/set fs readahead\n"
#ifdef HDIO_DRIVE_CMD
      " -A   set drive read-lookahead flag (0/1)\n"
#endif
#ifdef HDIO_GET_BUSSTATE
      " -b   get/set bus state (0 == off, 1 == on, 2 == tristate)\n"
#endif
      " -B   set Advanced Power Management setting (1-255)\n"
      " -c   get/set IDE 32-bit IO setting\n"
#ifdef HDIO_DRIVE_CMD
      " -C   check IDE power mode status\n"
#endif
#ifdef HDIO_SET_DMA
      " -d   get/set using_dma flag\n"
#endif
      " --direct  use O_DIRECT to bypass page cache for timings\n"
      " -D   enable/disable drive defect management\n"
#ifdef CDROM_SELECT_SPEED
      " -E   set cd-rom drive speed\n"
#endif
      " -f   flush buffer cache for device on exit\n"
      " -g   display drive geometry\n"
      " -h   display terse usage information\n"
      " -i   display drive identification\n"
      " -I   detailed/current information directly from drive\n"
      " --Istdin  reads identify data from stdin as ASCII hex\n"
      " --Istdout writes identify data to stdout as ASCII hex\n"
#ifdef HDIO_GET_KEEPSETTINGS
      " -k   get/set keep_settings_over_reset flag (0/1)\n"
#endif
#ifdef HDIO_DRIVE_CMD
      " -K   set drive keep_features_over_reset flag (0/1)\n"
      " -L   set drive doorlock (0/1) (removable harddisks only)\n"
#endif
#ifdef HDIO_GET_ACOUSTIC
      " -M   get/set acoustic management (0-254, 128: quiet, 254: fast) (EXPERIMENTAL)\n"
#endif /* HDIO_GET_ACOUSTIC */
      " -m   get/set multiple sector count\n"
#ifdef HDIO_SET_NOWERR
      " -n   get/set ignore-write-errors flag (0/1)\n"
#endif
#ifdef HDIO_SET_PIO_MODE
      " -p   set PIO mode on IDE interface chipset (0,1,2,3,4,...)\n"
#endif
#ifdef HDIO_DRIVE_CMD
      " -P   set drive prefetch count\n"
#endif
      " -q   change next setting quietly\n"
#ifdef HDIO_GET_QDMA
      " -Q   get/set DMA tagged-queuing depth (if supported)\n"
#endif
      " -r   get/set device  readonly flag (DANGEROUS to set)\n"
#ifdef HDIO_SCAN_HWIF
      " -R   register an IDE interface (DANGEROUS)\n"
#endif
#ifdef HDIO_DRIVE_CMD
      " -S   set standby (spindown) timeout\n"
#endif
      " -t   perform device read timings\n"
      " -T   perform cache read timings\n"
      " -u   get/set unmaskirq flag (0/1)\n"
#ifdef HDIO_UNREGISTER_HWIF
      " -U   un-register an IDE interface (DANGEROUS)\n"
#endif
      " -v   defaults; same as -mcudkrag for IDE drives\n"
      " -V   display program version and exit immediately\n"
#ifdef HDIO_DRIVE_CMD
#ifdef HDIO_DRIVE_RESET
      " -w   perform device reset (DANGEROUS)\n"
#endif
      " -W   set drive write-caching flag (0/1) (DANGEROUS)\n"
#ifdef HDIO_TRISTATE_HWIF
      " -x   tristate device for hotswap (0/1) (DANGEROUS)\n"
#endif
      " -X   set IDE xfer mode (DANGEROUS)\n"
      " -y   put IDE drive in standby mode\n"
      " -Y   put IDE drive to sleep\n"
      " -Z   disable Seagate auto-powersaving mode\n"
      " -z   re-read partition table\n"
#endif

#ifdef WIN_SECURITY_FREEZE_LOCK
      "\nATA Security Options:\n"
      " --security-freeze           Freeze security settings (until next reset)\n"
      " --security-unlock PWD       Unlock drive, using password PWD (DANGEROUS)\n"
      " --security-set-pass PWD     Lock drive, using password PWD (DANGEROUS)\n"
      " --security-disable PWD            Disable drive locking, using password PWD (DANGEROUS) \n"
      " --security-mode MODE        Specify user/master password and high/maximum security \n"
      "     u     user password, high security \n"
      "     U     user password, maximum security \n"
      "     m     master password, high security \n"
      "     M     master password, maximum security \n"
#endif
      );
      exit(ret);
}

#define GET_NUMBER(flag,num)  num = 0; \
                        if (!*p && argc && isdigit(**argv)) \
                              p = *argv++, --argc; \
                        while (isdigit(*p)) { \
                              flag = 1; \
                              num = (num * 10) + (*p++ - '0'); \
                        }

#define GET_STRING(flag, num) tmpstr = name; \
                        tmpstr[0] = '\0'; \
                        if (!*p && argc && isalnum(**argv)) \
                              p = *argv++, --argc; \
                        while (isalnum(*p) && (tmpstr - name) < 31) { \
                              tmpstr[0] = *p++; \
                              tmpstr[1] = '\0'; \
                              ++tmpstr; \
                        } \
                        num = translate_xfermode(name); \
                        if (num == -1) \
                              flag = 0; \
                        else \
                              flag = 1;

#define GET_ASCII_PASSWORD(flag, pwd) tmpstr = pwd; \
                        memset(&pwd,0,sizeof(pwd)); \
                        if (!*p && argc && isgraph(**argv)) \
                              p = *argv++, --argc; \
                        while ((tmpstr - pwd) < 32) { \
                              if (!isgraph(*p)) { \
                                    if (*p > 0) { \
                                          flag = 0; \
                                          printf("Abort: Password contains non-printable characters!"); \
                                    } else flag = 1; \
                                    break; \
                              } else {\
                                    sscanf(p,"%c",(unsigned char *) &tmpstr[0]); \
                                    p = p+1; \
                                    ++tmpstr; \
                              } \
                        }

static int fromhex (unsigned char c)
{
      if (c >= 'a' && c <= 'f')
            return 10 + (c - 'a');
      if (c >= '0' && c <= '9')
            return (c - '0');
      fprintf(stderr, "bad char: '%c' 0x%02x\n", c, c);
      exit(-1);
}

static int identify_from_stdin (void)
{
      unsigned short sbuf[800];
      unsigned char  buf[1600], *b = (unsigned char *)buf;
      int i, count;

      // skip leading cruft
      while (1 == read(0, buf, 1) && (*buf < '0' || *buf > '9') && (*buf < 'a' || *buf > 'f'))
            while (1 == read(0, buf, 1) && *buf != '\n');

      count = read(0, buf+1, 1279);
      if (count != 1279) {
            fprintf(stderr, "read(1279 bytes) failed (rc=%d)", count);
            perror("");
            exit(errno);
      }
      for (i = 0; count >= 4; ++i) {
            sbuf[i] = (fromhex(b[0]) << 12) | (fromhex(b[1]) << 8) | (fromhex(b[2]) << 4) | fromhex(b[3]);
            __le16_to_cpus((__u16 *)(&sbuf[i]));
            b += 5;
            count -= 5;
      }
      identify(sbuf, NULL);
      return 0;
}

int main(int argc, char **argv)
{
      char c, *p, *p1;
      char *tmpstr;
      char name[32];
      int neg;

      if  ((progname = (char *) strrchr(*argv, '/')) == NULL)
            progname = *argv;
      else
            progname++;
      ++argv;

      if (!--argc)
            usage_error(1);
      while (argc--) {
            p = *argv++;
            if (*p == '-') {
                  if (0 == strcmp(p, "--direct")) {
                        open_flags |= O_DIRECT;
                        continue;
                  }
                  if (0 == strcmp(p, "--Istdin")) {
                        identify_from_stdin();
                        continue;
                  }
                  if (0 == strcmp(p, "--Istdout")) {
                        get_IDentity = 2;
                        continue;
                  }
                  if (!*++p)
                        usage_error(1);
                  while ((c = *p++)) {
                        ++flagcount;
                        switch (c) {
                              case 'V':
                                    fprintf(stdout, "%s %s\n", progname, VERSION);
                                    exit(0);
                                    break;
                              case 'v':
                                    verbose = 1;
                                    break;
                              case 'I':
                                    get_IDentity = 1;
                                    break;
                              case 'i':
                                    get_identity = 1;
                                    break;
                              case 'g':
                                    get_geom = 1;
                                    break;
                              case 'f':
                                    do_flush = 1;
                                    break;
                              case 'q':
                                    quiet = 1;
                                    noisy = 0;
                                    break;
                              case 'u':
                                    get_unmask = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_unmask = 1;
                                          unmask = *p++ - '0';
                                    }
                                    break;
#ifdef HDIO_SET_DMA
                              case 'd':
                                    get_dma = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p >= '0' && *p <= '9') {
                                          set_dma = 1;
                                          dma = *p++ - '0';
                                    }
                                    break;
#endif
#ifdef HDIO_SET_NOWERR
                              case 'n':
                                    get_nowerr = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_nowerr = 1;
                                          nowerr = *p++ - '0';
                                    }
                                    break;
#endif
#ifdef HDIO_SET_PIO_MODE
                              case 'p':
                                    noisy_piomode = noisy;
                                    noisy = 1;
                                    GET_STRING(set_piomode,piomode);
                                    break;
#endif
                              case 'r':
                                    get_readonly = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_readonly = 1;
                                          readonly = *p++ - '0';
                                    }
                                    break;
                              case 'm':
                                    get_mult = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_mult,mult);
                                    break;
                              case 'c':
                                    get_io32bit = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_io32bit,io32bit);
                                    break;
#ifdef HDIO_DRIVE_CMD
                              case 'S':
                                    get_standby = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_standby,standby_requested);
                                    if (!set_standby)
                                          fprintf(stderr, "-S: missing value\n");
                                    break;

                              case 'D':
                                    get_defects = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_defects,defects);
                                    if (!set_defects)
                                          fprintf(stderr, "-D: missing value\n");
                                    break;
#ifdef CDROM_SELECT_SPEED
                              case 'E':
                                    set_cdromspeed = 1;
                                    GET_NUMBER(set_cdromspeed,cdromspeed);
                                    if (!set_cdromspeed)
                                          fprintf (stderr, "-s: missing value\n");
                                    break;
#endif /* CDROM_SELECT_SPEED */

                              case 'P':
                                    get_prefetch = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_prefetch,prefetch);
                                    if (!set_prefetch)
                                          fprintf(stderr, "-P: missing value\n");
                                    break;

                              case 'X':
                                    get_xfermode = noisy;
                                    noisy = 1;
                                    GET_STRING(set_xfermode,xfermode_requested);
                                    if (!set_xfermode)
                                          fprintf(stderr, "-X: missing value\n");
                                    break;

                              case 'K':
                                    get_dkeep = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_dkeep = 1;
                                          dkeep = *p++ - '0';
                                    } else
                                          fprintf(stderr, "-K: missing value (0/1)\n");
                                    break;

                              case 'A':
                                    get_lookahead = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_lookahead = 1;
                                          lookahead = *p++ - '0';
                                    } else
                                          fprintf(stderr, "-A: missing value (0/1)\n");
                                    break;

                              case 'L':
                                    get_doorlock = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_doorlock = 1;
                                          doorlock = *p++ - '0';
                                    } else
                                          fprintf(stderr, "-L: missing value (0/1)\n");
                                    break;

                              case 'W':
                                    get_wcache = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_wcache = 1;
                                          wcache = *p++ - '0';
                                    } else
                                          fprintf(stderr, "-W: missing value (0/1)\n");
                                    break;

                              case 'C':
                                    get_powermode = noisy;
                                    noisy = 1;
                                    break;

                              case 'y':
                                    get_standbynow = noisy;
                                    noisy = 1;
                                    set_standbynow = 1;
                                    break;

                              case 'Y':
                                    get_sleepnow = noisy;
                                    noisy = 1;
                                    set_sleepnow = 1;
                                    break;

                              case 'z':
                                    reread_partn = 1;
                                    break;

                              case 'Z':
                                    get_seagate = noisy;
                                    noisy = 1;
                                    set_seagate = 1;
                                    break;
#endif /* HDIO_DRIVE_CMD */
#ifdef HDIO_GET_KEEPSETTINGS
                              case 'k':
                                    get_keep = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          set_keep = 1;
                                          keep = *p++ - '0';
                                    }
                                    break;
#endif /* HDIO_GET_KEEPSETTINGS */
#ifdef HDIO_UNREGISTER_HWIF
                              case 'U':
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;

                                    if(! p) {
                                          fprintf(stderr, "expected hwif_nr\n");
                                          exit(1);
                                    }

                                    sscanf(p++, "%i", &hwif);

                                    unregister_hwif = 1;
                                    break;
#endif /* HDIO_UNREGISTER_HWIF */
#ifdef HDIO_SCAN_HWIF
                              case 'R':
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;

                                    if(! p) {
                                          fprintf(stderr, "expected hwif_data\n");
                                          exit(1);
                                    }

                                    sscanf(p++, "%i", &hwif_data);

                                    if (argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    else {
                                          fprintf(stderr, "expected hwif_ctrl\n");
                                          exit(1);
                                    }

                                    sscanf(p, "%i", &hwif_ctrl);

                                    if (argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    else {
                                          fprintf(stderr, "expected hwif_irq\n");
                                          exit(1);
                                    }

                                    sscanf(p, "%i", &hwif_irq);

                                    *p = '\0';

                                    scan_hwif = 1;
                                    break;
#endif /* HDIO_SCAN_HWIF */
#ifdef HDIO_GET_QDMA
                              case 'Q':
                                    get_dma_q = noisy;
                                    noisy = 1;
                                    neg = 0;
#ifdef HDIO_SET_QDMA
                                    GET_NUMBER(set_dma_q, dma_q);
                                    if (neg)
                                          dma_q = -dma_q;
#endif
                                    break;
#endif
#ifdef HDIO_DRIVE_RESET
                              case 'w':
                                    perform_reset = 1;
                                    break;
#endif /* HDIO_DRIVE_RESET */
#ifdef HDIO_TRISTATE_HWIF
                              case 'x':
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    if (*p == '0' || *p == '1') {
                                          perform_tristate = 1;
                                          tristate = *p++ - '0';
                                    } else
                                          fprintf(stderr, "-x: missing value (0/1)\n");
                                    break;

#endif /* HDIO_TRISTATE_HWIF */
                              case 'a':
                                    get_fsreadahead = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_fsreadahead,fsreadahead);
                                    break;
                              case 'B':
                                    get_apmmode = noisy;
                                    noisy = 1;
                                    GET_NUMBER(set_apmmode,apmmode);
                                    if (!set_apmmode)
                                    printf("-B: missing value (1-255)\n");
                                    break;
                              case 't':
                                    do_timings = 1;
                                    do_flush = 1;
                                    break;
                              case 'T':
                                    do_ctimings = 1;
                                    do_flush = 1;
                                    break;
#ifdef HDIO_GET_BUSSTATE
                              case 'b':
                                    get_busstate = noisy;
                                    noisy = 1;
                                    if (!*p && argc && isdigit(**argv))
                                          p = *argv++, --argc;
                                    switch (*p) {
                                          case '0':
                                          case '1':
                                          case '2':
                                                set_busstate = 1;
                                                busstate = *p++ - '0';
                                                break;
                                          default:
                                                break;
                                    }
                                    break;
#endif
#ifdef HDIO_GET_ACOUSTIC
                              case 'M':
                                    get_acoustic = noisy; /* are we noisy? */
                                    noisy = 1;
                                    GET_NUMBER(set_acoustic,acoustic);
                                    break;
#endif /* HDIO_GET_ACOUSTIC */
                              case 'h':
                                    usage_error(0);
                                    break;
                              case 'F':
                                    set_freeze = 1;
                                    break;
                              case '-':
                                    p1=p;       //Save Switch-String
                                    while (isgraph(*p))
                                          p++;  //Move P forward
#ifdef WIN_SECURITY_FREEZE_LOCK
                                    if (0 == strcmp(p1, "security-freeze")) {
                                          set_freeze = 1;
                                    } else if (0 == strcmp(p1, "security-unlock")) {
                                          open_flags = O_RDWR;
                                          set_security = 1;
                                          security_command = WIN_SECURITY_UNLOCK;
                                          GET_ASCII_PASSWORD(set_security,security_password);
                                    } else if (0 == strcmp(p1, "security-set-pass")) {
                                          open_flags=O_RDWR;
                                          set_security = 1;
                                          security_command = WIN_SECURITY_SET_PASS;
                                          GET_ASCII_PASSWORD(set_security,security_password);
                                    } else if (0 == strcmp(p1, "security-disable")) {
                                          open_flags = O_RDWR;
                                          set_security = 1;
                                          security_command = WIN_SECURITY_DISABLE;
                                          GET_ASCII_PASSWORD(set_security,security_password);
                                    } else if (0 == strcmp(p1, "security-mode")) {
                                          if (!*p && argc && isalpha(**argv))
                                                p = *argv++, --argc;
                                          switch (*p) {
                                                case 'u':
                                                      security_master = 0;
                                                      security_mode   = 0;
                                                      break;
                                                case 'U':
                                                      security_master = 0;
                                                      security_mode   = 1;
                                                      break;
                                                case 'm':
                                                      security_master = 1;
                                                      security_mode   = 0;
                                                      break;
                                                case 'M':
                                                      security_master = 1;
                                                      security_mode   = 1;
                                                      break;
                                                default:
                                                      security_master = 0;
                                                      security_mode   = 0;
                                                      break;
                                          }
                                          ++p;
                                    }
                                    break;
#endif
                              default:
                                    usage_error(1);
                        }
                  }
                  if (!argc)
                        usage_error(1);
            } else {
                  process_dev (p);
            }
      }
      exit (0);
}

Generated by  Doxygen 1.6.0   Back to index