"Fossies" - the Fresh Open Source Software Archive

Member "hdparm-9.65/contrib/fix_standby.c" (12 Oct 2016, 5704 Bytes) of package /linux/misc/hdparm-9.65.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fix_standby.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * fix_standby.c  by Mark Lord, March 2006.
    3  *
    4  * This frees a drive from the "power up in standby" condition.
    5  * It tries to be safe, but is still quite risky when run
    6  * on a preemptive kernel, because it could preempt something
    7  * that was in the middle of issuing an IDE/SATA command.
    8  *
    9  * Hardcoded to work only on the first (master) drive
   10  * on the first (primary) IDE/SATA interface.
   11  */
   12 #include <stdio.h>
   13 #include <errno.h>
   14 #include <stdlib.h>
   15 #include <unistd.h>
   16 #include <sys/io.h>
   17 
   18 typedef unsigned char  u8;
   19 typedef unsigned short u16;
   20 
   21 enum {
   22     BUSY_STAT   = 0x80,
   23     READY_STAT  = 0x40,
   24     WRERR_STAT  = 0x20,
   25     SEEK_STAT   = 0x10,
   26     DRQ_STAT    = 0x08,
   27     ECC_STAT    = 0x04,
   28     INDEX_STAT  = 0x02,
   29     ERR_STAT    = 0x01,
   30 };
   31 
   32 enum {
   33     CHECKPOWERMODE  = 0xE5,
   34     SETFEATURES = 0xEF,
   35     SF_SPINUP_NOW   = 0x07,
   36     SF_NO_STANDBY   = 0x86,
   37 };
   38 
   39 static unsigned int ide_base, ide_control, ide_altstatus;
   40 
   41 enum {
   42     ide_data    = 0,
   43     ide_feature = 1,
   44     ide_error   = ide_feature,
   45     ide_nsectors    = 2,
   46     ide_lbal    = 3,
   47     ide_lbam    = 4,
   48     ide_lbah    = 5,
   49     ide_select  = 6,
   50     ide_command = 7,
   51     ide_status  = ide_command,
   52 };
   53 
   54 static inline void
   55 cli (void)
   56 {
   57     __asm__ __volatile__("cli" : : : "memory");
   58 }
   59 
   60 static inline void
   61 sti (void)
   62 {
   63     __asm__ __volatile__("sti" : : : "memory");
   64 }
   65 
   66 static void
   67 wait_400ns (void)
   68 {
   69     inb(ide_altstatus);
   70     inb(ide_altstatus);
   71     inb(ide_altstatus);
   72     inb(ide_altstatus);
   73     inb(ide_altstatus);
   74 }
   75 
   76 static inline void
   77 OUTB (u8 val, unsigned int reg)
   78 {
   79     outb(val, ide_base + reg);
   80 }
   81 
   82 static inline u8
   83 INB (unsigned int reg)
   84 {
   85     return inb(ide_base + reg);
   86 }
   87 
   88 static inline u16
   89 INW (unsigned int reg)
   90 {
   91     return inw(ide_base + reg);
   92 }
   93 
   94 static inline void
   95 OUTW (u16 val, unsigned int reg)
   96 {
   97     outw(val, ide_base + reg);
   98 }
   99 
  100 static void
  101 dump_regs (void)
  102 {
  103     printf("ide_data      = 0x%04x\n", INW(ide_data));
  104     printf("ide_error     = 0x%02x\n", INB(ide_error));
  105     printf("ide_nsectors  = 0x%02x\n", INB(ide_nsectors));
  106     printf("ide_lbal      = 0x%02x\n", INB(ide_lbal));
  107     printf("ide_lbam      = 0x%02x\n", INB(ide_lbam));
  108     printf("ide_lbah      = 0x%02x\n", INB(ide_lbah));
  109     printf("ide_select    = 0x%02x\n", INB(ide_select));
  110     printf("ide_status    = 0x%02x\n", INB(ide_status));
  111     printf("ide_altstatus = 0x%02x\n", INB(ide_altstatus));
  112 }
  113 
  114 static int
  115 wait_for_status (u8 ones, u8 zeros, u8 *stat_r, unsigned int timeout)
  116 {
  117     u8 stat;
  118     int result;
  119 
  120     wait_400ns();
  121     timeout *= 1000000;
  122     do {
  123         stat = INB(ide_status);
  124         result = (stat & (ones|zeros)) != ones;
  125     } while (result && --timeout);
  126     if (stat_r)
  127         *stat_r = stat;
  128     return result ? EIO : 0;
  129 }
  130 
  131 static int
  132 require_status (u8 ones, u8 zeros, u8 *stat_r, unsigned int timeout, const char *msg)
  133 {
  134     int result = 0;
  135     u8 stat;
  136 
  137     if (wait_for_status(ones, zeros, &stat, timeout)) {
  138         fprintf(stderr, "status timeout: %s, stat=0x%02x\n", msg, stat);
  139         dump_regs();
  140         result = EIO;
  141     }
  142     if (stat_r)
  143         *stat_r = stat;
  144     return result;
  145 }
  146 
  147 static int
  148 do_drive_select (int master_slave)
  149 {
  150     if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_drive_select1"))
  151         return EIO;
  152     OUTB(0xe0 | ((master_slave & 1) << 4), ide_select);
  153     if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_drive_select2"))
  154         return EIO;
  155     return 0;
  156 }
  157 
  158 static int
  159 do_nondata_command (u8 command)
  160 {
  161     u8 stat, err;
  162 
  163     if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_nondata_command1"))
  164         return EIO;
  165     OUTB(command, ide_command);
  166     if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, &stat, 40, "do_nondata_command2"))
  167         return EIO;
  168     if ((stat & ERR_STAT)) {
  169         err = INB(ide_error);
  170         fprintf(stderr, "command 0x%02x failed, status=0x%02x, error=0x%02x\n", command, stat, err);
  171         dump_regs();
  172         return EIO;
  173     }
  174     printf("command 0x%02x succeeded\n", command);
  175     return 0;
  176 }
  177 
  178 static int
  179 do_setfeatures (u8 subcommand, u8 parameter)
  180 {
  181     if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_setfeatures1"))
  182         return EIO;
  183     OUTB(subcommand, ide_feature);
  184     OUTB(parameter,  ide_nsectors);
  185     return do_nondata_command(SETFEATURES);
  186 }
  187 
  188 static int
  189 do_rw_test (void)
  190 {
  191     OUTW(0x1234, ide_data);
  192     wait_400ns();
  193     if (INW(ide_data) == 0x1234) {
  194         OUTW(0x4321, ide_data);
  195         wait_400ns();
  196         if (INW(ide_data) == 0x4321)
  197             return 0; /* success */
  198     }
  199     fprintf(stderr, "register read/write test failed\n");
  200     return EIO;
  201 }
  202 
  203 static int
  204 do_fix_drive (void)
  205 {
  206     u8 stat;
  207 
  208     printf("\nTrying with ide_base=0x%x:\n", ide_base);
  209 
  210     ide_control = (ide_base < 0x1000) ? 0x206 : 0x102;
  211     ide_altstatus = ide_control;
  212 
  213     stat = INB(ide_altstatus);
  214     if (stat == 0xff || stat == 0x00) {
  215         fprintf(stderr, "No drive detected, try a different ide_base?\n");
  216         return ENODEV;
  217     }
  218 
  219     if ((stat & (BUSY_STAT|DRQ_STAT))) {
  220         fprintf(stderr, "IDE interface is busy, try again later\n");
  221         return EAGAIN;
  222     }
  223     if (do_drive_select(0))
  224         return EIO;
  225     do_rw_test();
  226 
  227     OUTB(0x02, ide_control);        /* set NIEN */
  228     wait_400ns();
  229 
  230     if (do_setfeatures(SF_SPINUP_NOW, 0))   /* spin-up the drive */
  231         return EIO;
  232     if (do_setfeatures(SF_NO_STANDBY, 0))   /* disable powerup-in-standby feature */
  233         return EIO;
  234     if (do_nondata_command(CHECKPOWERMODE)) /* clear any leftover errors */
  235         return EIO;
  236     dump_regs();
  237 
  238     INB(ide_status);            /* clear IRQ */
  239     OUTB(0x00, ide_control);        /* reeanble NIEN */
  240     wait_400ns();
  241     INB(ide_status);            /* clear IRQ */
  242 
  243     printf("Done; the drive may take another 30 seconds to come to life now.\n");
  244     return 0;
  245 }
  246 
  247 int  main (int argc, char **argv)
  248 {
  249     int result;
  250 
  251     ide_base = 0x1f0;
  252     if (argc > 1) {
  253         char *end = NULL;
  254         ide_base = strtol(argv[1], &end, 0);
  255         if (argc > 2 || !ide_base || ide_base > 0xffff || !end || *end) {
  256             fprintf(stderr, "Bad argument; expected ide_base, Eg:  0x1f0\n");
  257             return EINVAL;
  258         }
  259     }
  260 
  261     sync();
  262     sleep(2);
  263     iopl(3);
  264     cli();
  265 
  266     result = do_fix_drive();
  267 
  268     sti();
  269     sync();
  270     return result;
  271 }
  272