VirtualBox

Changeset 73 in kStuff


Ignore:
Timestamp:
Dec 20, 2015 9:17:34 PM (9 years ago)
Author:
bird
Message:

xtide util hacking.

Location:
hacks/xtide
Files:
3 added
1 edited
2 copied

Legend:

Unmodified
Added
Removed
  • hacks/xtide/atalib.c

    r72 r73  
    3333#include <io.h>
    3434#include <conio.h>
    35 
    36 /*********************************************************************************************************************************
    37 *   Structures and Typedefs                                                                                                      *
    38 *********************************************************************************************************************************/
    39 typedef struct REGS16
    40 {
    41     uint16_t    ax;     /**<  0 */
    42     uint16_t    cx;     /**<  2 */
    43     uint16_t    dx;     /**<  4 */
    44     uint16_t    si;     /**<  6 */
    45     uint16_t    di;     /**<  8 */
    46     uint16_t    es;     /**< 10 */
    47     uint16_t    efl;    /**< 12 */
    48     uint16_t    ds;     /**< 14 */
    49     uint16_t    bx;     /**< 16 */
    50 } REGS16;
    51 
    52 #define X86_EFL_CF 1
    53 
    54 /* The necessary I/O ports, indexed by "bus". */
    55 #define ATA_PORT_SHIFT      1 /* For XT-CF trick */
    56 #define ATA_REG_DATA(x)             (x)
    57 #define ATA_REG_FEATURES(x)         ((x) + (1 << ATA_PORT_SHIFT))
    58 #define ATA_REG_SECTOR_COUNT(x)     ((x) + (2 << ATA_PORT_SHIFT))
    59 
    60 #define ATA_REG_SECTOR_NUMBER(x)    ((x) + (3 << ATA_PORT_SHIFT))
    61 #define ATA_REG_CYLINDER_LOW(x)     ((x) + (4 << ATA_PORT_SHIFT))
    62 #define ATA_REG_CYLINDER_HIGH(x)    ((x) + (5 << ATA_PORT_SHIFT))
    63 #define ATA_REG_HEAD(x)             ((x) + (6 << ATA_PORT_SHIFT))
    64 
    65 #define ATA_REG_LBA_0_7(x)          ((x) + (3 << ATA_PORT_SHIFT))
    66 #define ATA_REG_LBA_8_15(x)         ((x) + (4 << ATA_PORT_SHIFT))
    67 #define ATA_REG_LBA_16_23(x)        ((x) + (5 << ATA_PORT_SHIFT))
    68 #define ATA_REG_LBA_24_27_MODE(x)   ((x) + (6 << ATA_PORT_SHIFT))
    69 #define ATA_LBA_MODE                UINT8_C(0x40) /**< Selects LBA mode in ATA_REG_LBA_24_27_MODE. */
    70 
    71 #define ATA_REG_DEVICE_SELECT(x)    ((x) + (6 << ATA_PORT_SHIFT))
    72 #define ATA_REG_COMMAND(x)          ((x) + (7 << ATA_PORT_SHIFT))
    73 
    74 
    75 #define ATA_REG_STATUS(x)           ATA_REG_COMMAND(x)
    76 #define ATA_REG_ALT_STATUS(x)       ATA_REG_CONTROL(x)
    77 #define ATA_STS_BUSY                UINT8_C(0x80)
    78 #define ATA_STS_DRDY                UINT8_C(0x40)
    79 #define ATA_STS_DF                  UINT8_C(0x20)
    80 #define ATA_STS_DSC                 UINT8_C(0x10)
    81 #define ATA_STS_DRQ                 UINT8_C(0x08)
    82 #define ATA_STS_CORR                UINT8_C(0x04)
    83 #define ATA_STS_IDX                 UINT8_C(0x02)
    84 #define ATA_STS_ERR                 UINT8_C(0x01)
    85 
    86 #define ATA_REG_ERROR(x)            ATA_REG_FEATURES(x)
    87 #define ATA_ERR_RSVR                UINT8_C(0x80)
    88 #define ATA_ERR_UNC                 UINT8_C(0x40)
    89 #define ATA_ERR_MC                  UINT8_C(0x20)
    90 #define ATA_ERR_IDNF                UINT8_C(0x10)
    91 #define ATA_ERR_MCR                 UINT8_C(0x08)
    92 #define ATA_ERR_ABRT                UINT8_C(0x04)
    93 #define ATA_ERR_TKNONF              UINT8_C(0x02)
    94 #define ATA_ERR_AMNF                UINT8_C(0x01)
    95 
    96 #define ATA_REG_CONTROL(x)          ((x) + (14 << ATA_PORT_SHIFT))
    97 #define ATA_CTL_IEN                 UINT8_C(0x02) /**< Interrupt enable. */
    98 #define ATA_CTL_SRST                UINT8_C(0x04) /**< software reset */
    99 
    100 #define ATA_CMD_NOP                 UINT8_C(0x00)
    101 #define ATA_CMD_READ_SECTORS        UINT8_C(0x20)
    102 #define ATA_CMD_READ_SECTORS_NR     UINT8_C(0x21)
    103 #define ATA_CMD_READ_LONG           UINT8_C(0x22)
    104 #define ATA_CMD_READ_LONG_NR        UINT8_C(0x23)
    105 #define ATA_CMD_WRITE_SECTORS       UINT8_C(0x30)
    106 #define ATA_CMD_WRITE_SECTORS_NR    UINT8_C(0x31)
    107 #define ATA_CMD_WRITE_LONG          UINT8_C(0x32)
    108 #define ATA_CMD_WRITE_LONG_NR       UINT8_C(0x33)
    109 #define ATA_CMD_INIT_DEVICE_PARAMS  UINT8_C(0x91)
    110 #define ATA_CMD_SET_FEATURES        UINT8_C(0xef)
    111 #define ATA_CMD_IDENTIFY_DEVICE     UINT8_C(0xec)
    112 
    113 
    114 #define ATA_DEV_MASTER              UINT8_C(0x00)  /**< Master device selection bit value. */
    115 #define ATA_DEV_SLAVE               UINT8_C(0x10)  /**< Slave device selection bit value. */
    116 
    117 #define ATA_FEATURE_EN_8BIT_DATA        UINT8_C(0x01)
    118 #define ATA_FEATURE_DI_8BIT_DATA        UINT8_C(0x81)
    119 #define ATA_FEATURE_EN_WRITE_CACHE      UINT8_C(0x02)
    120 #define ATA_FEATURE_DI_WRITE_CACHE      UINT8_C(0x82)
    121 #define ATA_FEATURE_SET_XFERMODE        UINT8_C(0x03)
    122 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT             UINT8_C(0x00)
    123 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY    UINT8_C(0x01)
    124 #define ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG            UINT8_C(0x08)
    125 #define ATA_FV_XFERMODE_SWDMA_MODE_XXX_FLAG          UINT8_C(0x10)
    126 #define ATA_FV_XFERMODE_MWDMA_MODE_XXX_FLAG          UINT8_C(0x20)
    127 
    128 /** Delay a bit by reading PIC mask. Should take 4-5 bus cycles,
    129  * and thus be more than the required 400ns delay on old computers. */
    130 #define ATA_DELAY_400NS()   do { inp(0x21); } while (0)
    131 
     35#include "atalib.h"
     36
     37#define STR_TUPLE(a_szStr) a_szStr, sizeof(a_szStr) - 1
    13238
    13339
     
    13541*   Global Variables                                                                                                             *
    13642*********************************************************************************************************************************/
    137 uint16_t g_uBasePort   = 0x300;
    138 uint16_t g_uPortShift  = 1;
     43uint16_t g_uBasePort;
     44uint16_t g_uCtrlPort;
     45uint16_t g_uPortShift;
     46uint8_t  g_bDevice;
    13947uint8_t  g_fUseLbaMode = 1;
    140 uint8_t  g_f8BitData   = 1;
    141 uint8_t  g_bDevice     = ATA_DEV_MASTER;
    142 uint8_t  g_bDrv        = 0x80;
    143 
     48uint8_t  g_f8BitData;
     49uint8_t  g_fSupportsSetFeature8BitData;
     50uint8_t  g_fSupportsSetFeatureWriteCache;
     51uint8_t  g_fSupportsSetFeatureXferMode;
     52int8_t   g_fSupportsReadBuffer = -1;
     53int8_t   g_fSupportsWriteBuffer = -1;
    14454
    14555uint16_t g_cHeads;
     
    307217}
    308218
    309 ////static uint8_t AtaWaitForDataRequest(size_t cbLeft)
    310 ////{
    311 ////    uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    312 ////    uint8_t  bStsFirst = inp(uAltStsPort);
    313 ////    uint8_t  bSts = bStsFirst;
    314 ////    uint32_t cLoops = 0;
    315 ////    do
    316 ////    {
    317 ////        if (++cLoops & 0xffff)
    318 ////        {
    319 ////static unsigned x = 0;
    320 ////if (x < 16)
    321 ////{
    322 ////    printf("AtaWaitForDataRequest: bFirst=%#x bLast=%#x cbLeft=%#x\n", bStsFirst, bSts, cbLeft);
    323 ////    x++;
    324 ////}
    325 ////            break;
    326 ////        }
    327 ////        bSts = inp(uAltStsPort);
    328 ////    } while (!(bSts & (ATA_STS_DRQ | ATA_STS_ERR)));
    329 ////    return bSts;
    330 ////}
    331 
    332 void xchg(uint8_t volatile *pb);
    333 #pragma aux xchg = \
    334     "xchg [si], cx" \
    335     "xchg [si], cx" \
    336     "xchg [si], cx" \
    337     "xchg [si], cx" \
    338     parm [si] \
    339     modify exact [cx];
    340 
    341219void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
    342220{
    343 //    uint16_t        uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    344221    uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
    345 
     222    uint16_t const   *pu16      = (uint16_t const *)pvBuf;
     223
     224    cb >>= 1;
    346225    if (f8BitData)
    347226    {
    348 #if 0
    349         uint8_t const   * volatile pbSrc = (uint8_t const *)pvBuf;
    350         uint8_t volatile ab[64];
    351         uint8_t volatile *pb = &ab[0];
    352         while (((uintptr_t)pb & 0x1f) != 0x1f)
    353             pb++;
    354         //uint8_t  bSts1, bSts2;
    355 inp(0x21);
    356 xchg(pb);
    357 
    358         while (cb-- > 0)
    359         {
    360             uint8_t b = *pbSrc++;
    361             xchg(pb);
    362             outp(uDataPort, b);
    363             xchg(pb);
    364             b = *pbSrc++;
    365             xchg(pb);
    366 //inp(0x21);
    367             outp(uDataPort, b);
    368             xchg(pb);
    369 //inp(0x21);
    370             //if (cb < 30)
    371             //{
    372             //    if ((cb & 3) == 3)
    373             //        printf("bSts1=%#x bSts2=%#x ", bSts1, bSts2);
    374             //    else
    375             //        printf("bSts1=%#x bSts2=%#x\n", bSts1, bSts2);
    376             //}
    377         }
    378 inp(0x21);
    379 #else
    380         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    381         cb >>= 1;
    382227        while (cb-- > 0)
    383228        {
     
    386231            outp(uDataPort, (uint8_t)(u16 >> 8));
    387232        }
    388 #endif
    389233    }
    390234    else
    391     {
    392         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    393         cb >>= 1;
    394235        while (cb-- > 0)
    395             outp(uDataPort, *pu16++);
    396     }
     236            outpw(uDataPort, *pu16++);
    397237}
    398238
     
    403243        return AtaError(bSts, "Prepping for reading sector %lu", iSector);
    404244
    405 printf("AtaReadSector #2\n");
    406245    bSts = AtaSelectDevice(g_bDevice);
    407246    if (bSts & ATA_STS_ERR)
    408247        return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
    409248
    410 //printf("AtaReadSector #3\n");
    411249    outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
    412250    outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
    413251    AtaSetSectorAddress(iSector, g_bDevice);
    414252
    415 //printf("AtaReadSector #4\n");
    416253    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
    417254    if (bSts & ATA_STS_ERR)
     
    421258        return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
    422259
    423 
    424 //printf("AtaReadSector #5\n");
    425260    AtaReadData(pvBuf, 512, g_f8BitData);
    426 //printf("AtaReadSector #6: bSts=%#x\n", inp(ATA_REG_ALT_STATUS(g_uBasePort)));
    427261    bSts = inp(ATA_REG_STATUS(g_uBasePort));
    428     if ((bSts & ATA_STS_DRQ))
     262    if (bSts & ATA_STS_DRQ)
    429263        return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
    430     if ((bSts & ATA_STS_ERR))
     264    if (bSts & ATA_STS_ERR)
    431265        return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
    432266    return 0;
     
    435269int AtaWriteSector(uint32_t iSector, void const *pvBuf)
    436270{
    437 //int x = printf("AtaWriteSector #1\n");
    438271    uint8_t bSts = AtaWaitBusy();
    439272    if (bSts & ATA_STS_ERR)
    440273        return AtaError(bSts, "Prepping for writing sector %lu", iSector);
    441 printf("AtaWriteSector #2\n");
    442274
    443275    bSts = AtaSelectDevice(g_bDevice);
     
    449281    AtaSetSectorAddress(iSector, g_bDevice);
    450282
    451 //printf("AtaWriteSector #3\n");
    452283    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
    453284    if (bSts & ATA_STS_ERR)
     
    456287        return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
    457288
    458 //printf("AtaWriteSector #4\n");
    459289    AtaWriteData(pvBuf, 512, g_f8BitData);
    460 //printf("AtaWriteSector #5\n");
    461290    ATA_DELAY_400NS();
    462291    bSts = AtaWaitBusy();
    463 //printf("AtaWriteSector #6\n");
    464292    if (bSts & ATA_STS_ERR)
    465293        return AtaError(bSts, "writing sector (#2) %lu", iSector);
    466294    if (bSts & ATA_STS_DRQ)
    467295        return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
     296
     297    return 0;
     298}
     299
     300
     301/**
     302 * @param pvBuf     Pointer to a 512-byte buffer.
     303 */
     304int AtaReadBuffer(void *pvBuf, uint8_t fExtraChecks)
     305{
     306    uint8_t bSts;
     307
     308    if (!g_fSupportsReadBuffer)
     309        return -2;
     310
     311    bSts = AtaWaitBusy();
     312    if (bSts & ATA_STS_ERR)
     313        return AtaError(bSts, "Prepping for reading buffer");
     314
     315    bSts = AtaSelectDevice(g_bDevice);
     316    if (bSts & ATA_STS_ERR)
     317        return AtaError(bSts, "Selecting device for reading buffer");
     318
     319    outp(ATA_REG_FEATURES(g_uBasePort),         0);
     320    outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     1); /* ignored */
     321    outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
     322    outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
     323    outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
     324
     325    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_BUFFER);
     326    if (bSts & ATA_STS_ERR)
     327        return AtaError(bSts, "Reading buffer");
     328
     329    if (!(bSts & ATA_STS_DRQ))
     330        return AtaError(bSts, "DRQ not set after reading buffer");
     331
     332    if (!fExtraChecks)
     333        AtaReadData(pvBuf, 512, g_f8BitData);
     334    else
     335        AtaReadData(pvBuf, 512, g_f8BitData);
     336    bSts = inp(ATA_REG_STATUS(g_uBasePort));
     337    if (bSts & ATA_STS_DRQ)
     338        return AtaError(bSts, "DRQ is still set after reading buffer");
     339    if (bSts & ATA_STS_ERR)
     340        return AtaError(bSts, "ERR is set after reading buffer");
     341    return 0;
     342}
     343
     344int AtaWriteBuffer(void const *pvBuf, uint8_t fExtraChecks)
     345{
     346    uint8_t bSts;
     347
     348    if (!g_fSupportsWriteBuffer)
     349        return -2;
     350
     351    bSts = AtaWaitBusy();
     352    if (bSts & ATA_STS_ERR)
     353        return AtaError(bSts, "Prepping for writing buffer");
     354
     355    bSts = AtaSelectDevice(g_bDevice);
     356    if (bSts & ATA_STS_ERR)
     357        return AtaError(bSts, "Selecting device for writing buffer");
     358
     359    outp(ATA_REG_FEATURES(g_uBasePort),         0);
     360    outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     1); /* ignored */
     361    outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
     362    outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
     363    outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
     364
     365    bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
     366    if (bSts & ATA_STS_ERR)
     367        return AtaError(bSts, "writing buffer (#1)");
     368    if (!(bSts & ATA_STS_DRQ))
     369        return AtaError(bSts, "DRQ not set after writing buffer (#1)");
     370
     371    if (!fExtraChecks)
     372        AtaWriteData(pvBuf, 512, g_f8BitData);
     373    else
     374        AtaWriteData(pvBuf, 512, g_f8BitData);
     375    ATA_DELAY_400NS();
     376    bSts = AtaWaitBusy();
     377    if (bSts & ATA_STS_ERR)
     378        return AtaError(bSts, "writing buffer (#2)");
     379    if (bSts & ATA_STS_DRQ)
     380        return AtaError(bSts, "DRQ is set after writing buffer (#2)");
    468381
    469382    return 0;
     
    571484}
    572485
    573 
    574 int AtaInit(void)
    575 {
    576     uint8_t bSts = inp(ATA_REG_ALT_STATUS(g_uBasePort));
    577     printf("alt status=");
     486int AtaReInit(void)
     487{
     488    int rc;
     489
     490    /* Reset the controller + devices. */
     491    if (AtaReset() != 0)
     492        return -1;
     493
     494    if (g_fSupportsSetFeature8BitData)
     495    {
     496        if (g_f8BitData)
     497            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
     498        else
     499            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
     500        if (rc != 0)
     501            return rc;
     502    }
     503
     504    /* Try disable write cache. */
     505    if (g_fSupportsSetFeatureWriteCache)
     506    {
     507        rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
     508        if (rc != 0)
     509            return rc;
     510    }
     511
     512    /* Select PIO mode without IORDY. */
     513    if (g_fSupportsSetFeatureXferMode)
     514    {
     515        rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
     516        if (rc != 0)
     517            return rc;
     518    }
     519
     520    return 0;
     521}
     522
     523int AtaInit(uint16_t uBasePort, uint16_t uCtrlPort, uint8_t uPortShift, uint8_t bDevice, uint8_t f8BitData)
     524{
     525    int rc;
     526    uint8_t bSts, bStsAlt;
     527
     528    g_uBasePort  = uBasePort;
     529    g_uCtrlPort  = uCtrlPort;
     530    g_uPortShift = uPortShift;
     531    g_bDevice    = bDevice;
     532    g_f8BitData  = f8BitData;
     533    g_fSupportsSetFeature8BitData = 1;
     534    g_fSupportsSetFeatureWriteCache = 1;
     535    g_fSupportsSetFeatureXferMode = 1;
     536
     537    /* Check whether the two status registers match up. If they don't we
     538       probably don't have a controller at this address. */
     539    inp(ATA_REG_STATUS(g_uBasePort));
     540    bSts    = inp(ATA_REG_STATUS(g_uBasePort));
     541    bStsAlt = inp(ATA_REG_ALT_STATUS(g_uBasePort));
     542    if (bSts != bStsAlt || bSts == 0xff)
     543    {
     544        fprintf(stderr, "Status register differs or is 0xff\n");
     545        fprintf(stderr, "     status=");
     546        AtaPrintStatus(stdout, bSts);
     547        fprintf(stderr, "\n");
     548        fprintf(stderr, " alt status=");
     549        AtaPrintStatus(stdout, bStsAlt);
     550        fprintf(stderr, "\n");
     551        return -1;
     552    }
     553    printf("Pre init status=");
    578554    AtaPrintStatus(stdout, bSts);
    579555    printf("\n");
    580556
    581     bSts = inp(ATA_REG_STATUS(g_uBasePort));
    582     printf("    status=");
    583     AtaPrintStatus(stdout, bSts);
    584     printf("\n");
    585 
    586     if (AtaReset() != 0)
    587         return -1;
    588 
    589     /* Enable 8-bit data transfers (just to be on the safe side). */
    590     AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
    591 
    592     /* Identify the device. */
    593     memset(g_awIdentify, 0, sizeof(g_awIdentify));
    594     if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
    595         return -1;
    596 
    597     /** @todo this is rather simple... */
    598     g_cCylinders = g_awIdentify[1];
    599     g_cHeads     = g_awIdentify[3];
    600     g_cSectorsPerTrack = g_awIdentify[6];
    601     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    602     printf("Device %#x parameters: %u cylinders, %u heads, %u sectors\n",
    603            g_bDevice, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    604 
    605     /* Disable stuff and try select pio modes. */
    606     AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
    607     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
    608     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG | 0);
    609 
    610     return 0;
    611 }
    612 
    613 
    614 
    615 
    616 /*
    617  * INT13h access methods
    618  * INT13h access methods
    619  * INT13h access methods
    620  */
    621 
    622 void BiosCall13(REGS16 *pRegs);
    623 #pragma aux BiosCall13 = \
    624     "push   ax" \
    625     "push   cx" \
    626     "push   dx" \
    627     "push   bp" \
    628     "push   si" \
    629     "push   di" \
    630     "push   es" \
    631     "push   bx" \
    632     "push   ds" \
    633     \
    634     "mov    ax,  [bx]" \
    635     "mov    cx,  [bx +  2]" \
    636     "mov    dx,  [bx +  4]" \
    637     "mov    si,  [bx +  6]" \
    638     "mov    di,  [bx +  8]" \
    639     "mov    es,  [bx + 10]" \
    640     "push   word ptr [bx + 12]" \
    641     "popf" \
    642     "push   word ptr [bx + 14]" \
    643     "push   word ptr [bx + 16]" \
    644     "pop    bx" \
    645     "pop    ds" \
    646     \
    647     "int    13h"\
    648     \
    649     "push   ds" \
    650     "push   bx" \
    651     "mov    bp, sp" \
    652     "mov    ds, [bp + 4]" \
    653     "mov    bx, [bp + 6]" \
    654     "mov    [bx], ax" \
    655     "mov    [bx +  2], cx" \
    656     "mov    [bx +  4], dx" \
    657     "mov    [bx +  6], si" \
    658     "mov    [bx +  8], di" \
    659     "mov    [bx + 10], es" \
    660     "pushf" \
    661     "pop    ax" \
    662     "mov    [bx + 12], ax" \
    663     "pop    ax" \
    664     "mov    [bx + 14], ax" \
    665     "pop    ax" \
    666     "mov    [bx + 16], ax" \
    667     \
    668     "pop    ds" \
    669     "pop    bx" \
    670     "pop    es" \
    671     "pop    di" \
    672     "pop    si" \
    673     "pop    bp" \
    674     "pop    dx" \
    675     "pop    cx" \
    676     "pop    ax" \
    677     parm [bx];
    678 
    679 
    680 int Int13hInit(void)
    681 {
    682     REGS16 Regs;
    683     memset(&Regs, 0, sizeof(Regs));
    684     Regs.ax = 0x0800;
    685     Regs.dx = g_bDrv;
    686     BiosCall13(&Regs);
    687     /** @todo check for errors.   */
    688     g_cHeads = (Regs.dx >> 8) + 1;
    689     g_cSectorsPerTrack = Regs.cx & 0x3f;
    690     g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2);
    691     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    692 
    693     printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n",
    694            g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    695     if (!(Regs.efl & X86_EFL_CF))
    696         return 0;
    697     fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax);
    698     return -1;
    699 }
    700 
    701 void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs)
    702 {
    703     uint16_t iRem = iSector % g_cSectorsPerCylinder;
    704     uint16_t iCyl = iSector / g_cSectorsPerCylinder;
    705     pRegs->cx  = iCyl << 8;
    706     pRegs->cx |= (iCyl >> 2) & 0xc0;
    707     pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f;
    708     pRegs->dx &= UINT16_C(0x00ff);
    709     pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8;
    710 }
    711 
    712 int Int13hReadSector(uint32_t iSector, void *pvBuf)
    713 {
    714     REGS16   Regs;
    715     memset(&Regs, 0, sizeof(Regs));
    716     Regs.ax = 0x0201;
    717     Regs.dx = g_bDrv;
    718     Regs.bx = (unsigned)(void __near *)pvBuf;
    719     Regs.es = (__segment)pvBuf;
    720     SectorNoToInt13(iSector, &Regs);
    721     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
    722     BiosCall13(&Regs);
    723     if (!(Regs.efl & X86_EFL_CF))
    724         return 0;
    725     fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
    726     return -1;
    727 }
    728 
    729 int Int13hWriteSector(uint32_t iSector, void const *pvBuf)
    730 {
    731     REGS16   Regs;
    732     memset(&Regs, 0, sizeof(Regs));
    733     Regs.ax = 0x0301;
    734     Regs.dx = g_bDrv;
    735     Regs.bx = (unsigned)(void const __near *)pvBuf;
    736     Regs.es = (__segment)pvBuf;
    737     SectorNoToInt13(iSector, &Regs);
    738     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
    739     BiosCall13(&Regs);
    740     if (!(Regs.efl & X86_EFL_CF))
    741         return 0;
    742     fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
    743     return -1;
    744 }
    745 
    746 
    747 
    748 int GetDriveParams(void)
    749 {
    750 #ifdef USE_INT13H
    751     return Int13hInit();
     557    for (;;)
     558    {
     559        /* Reset the controller + devices. */
     560        if (AtaReset() != 0)
     561            return -1;
     562
     563        /* Enable 8-bit data transfers (just to be on the safe side). */
     564        if (g_fSupportsSetFeature8BitData)
     565        {
     566            if (g_f8BitData)
     567                rc = AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
     568            else
     569                rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_8BIT_DATA, 0);
     570            if (rc != 0)
     571            {
     572                fprintf(stderr,
     573                        f8BitData
     574                        ? "warning: ATA_FEATURE_EN_8BIT_DATA failed, assuming not supported. Retrying in 16-bit mode."
     575                        : "warning: ATA_FEATURE_DI_8BIT_DATA failed, assuming not supported. Retrying.");
     576                g_fSupportsSetFeature8BitData = 0;
     577                g_f8BitData = 0;
     578                continue;
     579            }
     580        }
     581
     582        /* Try disable write cache. */
     583        if (g_fSupportsSetFeatureWriteCache)
     584        {
     585            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
     586            if (rc != 0)
     587            {
     588                fprintf(stderr, "warning: ATA_FEATURE_DI_WRITE_CACHE failed, assuming not supported. Retrying.");
     589                g_fSupportsSetFeatureWriteCache = 0;
     590                continue;
     591            }
     592        }
     593
     594        /* Select PIO mode without IORDY. */
     595        if (g_fSupportsSetFeatureXferMode)
     596        {
     597            rc = AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
     598            if (rc != 0)
     599            {
     600                fprintf(stderr, "warning: ATA_FEATURE_SET_XFERMODE = DEFAULT_NO_IORDY failed, assuming not supported. Retrying.");
     601                g_fSupportsSetFeatureXferMode = 0;
     602                continue;
     603            }
     604        }
     605
     606        /* Identify the device. */
     607        memset(g_awIdentify, 0, sizeof(g_awIdentify));
     608        if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
     609            return -1;
     610
     611        /** @todo this is rather simple... */
     612        g_cCylinders = g_awIdentify[1];
     613        g_cHeads     = g_awIdentify[3];
     614        g_cSectorsPerTrack = g_awIdentify[6];
     615        g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
     616        printf("Device %#x at %#x/%#x: %u cylinders, %u heads, %u sectors, %s data\n",
     617               g_bDevice, g_uBasePort, g_uCtrlPort, g_cCylinders, g_cHeads, g_cSectorsPerTrack,
     618               g_f8BitData ? "8-bit" : "16-bit");
     619
     620        /* Figure 5-9 in SanDisk Manual Rev 12.0: */
     621        if (   (g_awIdentify[83] & UINT16_C(0xc00)) == UINT16_C(0x4000)
     622            && (g_awIdentify[84] & UINT16_C(0xc00)) == UINT16_C(0x4000))
     623        {
     624            g_fSupportsWriteBuffer = (g_awIdentify[82] & UINT16_C(0x1000)) != 0;
     625            g_fSupportsReadBuffer  = (g_awIdentify[82] & UINT16_C(0x2000)) != 0;
     626        }
     627        printf("  %s WRITE_BUFFER, %s READ_BUFFER\n",
     628               g_fSupportsWriteBuffer == 1 ? "have" : g_fSupportsWriteBuffer == 0 ? "no" : "uncertain",
     629               g_fSupportsReadBuffer  == 1 ? "have" : g_fSupportsReadBuffer  == 0 ? "no" : "uncertain");
     630    }
     631
     632    return 0;
     633}
     634
     635int AtaArgMatchWithValue(const char *pszArg, const char *pszMatch, size_t cchMatch,
     636                         int cArgs, char **papszArgs, int *piArg, const char **ppszValue)
     637{
     638    if (strncmp(pszArg, pszMatch, cchMatch) == 0)
     639    {
     640        pszArg += cchMatch;
     641        if (!*pszArg)
     642        {
     643            if (*piArg < cArgs)
     644            {
     645                *ppszValue = papszArgs[*piArg];
     646                *piArg += 1;
     647            }
     648            else
     649            {
     650                fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
     651                *ppszValue = NULL;
     652            }
     653            return 1;
     654        }
     655
     656        if (*pszArg == ':' || *pszArg == '=')
     657        {
     658            if (!*pszArg)
     659                fprintf(stderr, "syntax error: Option '%s' is missing argument value\n", pszMatch);
     660            *ppszValue = pszArg;
     661            return 1;
     662        }
     663    }
     664
     665    return 0;
     666}
     667
     668int AtaInitFromArgv(int iArg, int cArgs, char **papszArgs)
     669{
     670    uint8_t  bDevice    = ATA_DEV_MASTER;
     671#if 0
     672    uint16_t uBasePort  = 0x1f0;    /* Primary ATA host controller. */
     673    uint16_t uCtrlPort  = 0x3f0;    /* The control block of the primary ATA host controller. */
     674    uint8_t  cShiftPort = 0;
     675    uint8_t  f8BitData  = 0;
    752676#else
    753     return AtaInit();
     677    uint16_t uBasePort  = 0x300;    /* Lo-tech CF-lite. */
     678    uint16_t uCtrlPort  = 0x310;    /* Lo-tech CF-lite. */
     679    uint8_t  cShiftPort = 1;        /* Special Lo-tech CF-lite hack. */
     680    uint8_t  f8BitData  = 1;
    754681#endif
    755 }
    756 
    757 int ReadSector(uint32_t iSector, void *pvBuf)
    758 {
    759 #ifdef USE_INT13H
    760     return Int13hReadSector(iSector, pvBuf);
    761 #else
    762     return AtaReadSector(iSector, pvBuf);
    763 #endif
    764 }
    765 
    766 int WriteSector(uint32_t iSector, void const *pvBuf)
    767 {
    768 #ifdef USE_INT13H
    769     return Int13hWriteSector(iSector, pvBuf);
    770 #else
    771     return AtaWriteSector(iSector, pvBuf);
    772 #endif
    773 }
    774 
    775 
    776 
    777 
    778 static int usage(void)
    779 {
    780     printf("usage: writetst [sector] [drv]\n");
    781     return 1;
    782 }
    783 
    784 
    785 int main(int argc, char **argv)
    786 {
    787     int rc = 1;
    788 
    789     /*
    790      * Parse parameters.
    791      */
    792     uint32_t iSector = 3;
    793     g_bDrv = 0x80;
    794     g_bDevice = ATA_DEV_MASTER;
    795 
    796     if (argc > 3)
    797     {
    798         fprintf(stderr, "too many parameters!\n");
    799         return usage();
    800     }
    801     if (argc > 1)
    802     {
    803         iSector = strtoul(argv[1], NULL, 0);
    804         if (   iSector == 0
    805             || (iSector >= 32 && iSector < 65535)
    806             || iSector > 0x800000 /*4G*/)
    807         {
    808             fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector);
    809             return usage();
    810         }
    811     }
    812     if (argc > 2)
    813     {
    814         unsigned long uTmp = strtoul(argv[2], NULL, 0);
    815         if (uTmp < 0x80 || uTmp > 0x8f)
    816         {
    817             fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp);
    818             return usage();
    819         }
    820         g_bDrv = (uint8_t)uTmp;
    821         g_bDevice = g_bDrv == 0x80 ? ATA_DEV_MASTER : ATA_DEV_SLAVE; /* simplified */
    822     }
    823 
    824     /*
    825      * Detect drive parameters.
    826      */
    827     if (GetDriveParams() == 0)
    828     {
    829         static uint8_t s_abSaved[512];
    830         if (ReadSector(iSector, s_abSaved) == 0)
    831         {
    832             static uint8_t s_abWrite[512];
    833             unsigned i;
    834             unsigned cTries;
    835             //unsigned cMaxTries = 20;
    836             unsigned cMaxTries = 1;
    837 
    838             for (i = 0; i < 512; i++)
    839                 s_abWrite[i] = (uint8_t)i;
    840 
    841             for (cTries = 0; cTries < cMaxTries && rc != 0; cTries++)
     682
     683    while (iArg < cArgs)
     684    {
     685        const char *pszArg = papszArgs[iArg++];
     686        const char *pszValue;
     687        int         iWhich = 0;
     688        if (   (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--base-port"), cArgs, papszArgs, &iArg, &pszValue))
     689            || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-b"), cArgs, papszArgs, &iArg, &pszValue))
     690            || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("--ctrl-port"), cArgs, papszArgs, &iArg, &pszValue) * 2)
     691            || (iWhich = AtaArgMatchWithValue(pszArg, STR_TUPLE("-c"), cArgs, papszArgs, &iArg, &pszValue)          * 2) )
     692         {
     693            unsigned long uTmp = strtoul(pszValue, NULL, 16);
     694            if (uTmp < 16 || uTmp >= 1024)
    842695            {
    843                 if (WriteSector(iSector, s_abWrite) == 0)
    844                 {
    845                     static uint8_t s_abReadBack[512];
    846 
    847                     if (ReadSector(iSector, s_abReadBack) == 0)
    848                     {
    849                         for (i = 0; i < 512; i++)
    850                             s_abWrite[i] = (uint8_t)i;
    851 
    852                         if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0)
    853                         {
    854                             rc = 0;
    855                             printf("wrote sector and successfully read it back\n");
    856                         }
    857                         else if (cTries >= cMaxTries - 1)
    858                         {
    859                             unsigned cErrors = 0;
    860                             fprintf(stderr, "read back doesn't match what was written:\n");
    861                             for (i = 0; i < 512; i++)
    862                                 if (s_abReadBack[i] != (uint8_t)i)
    863                                 {
    864                                     fprintf(stderr,  "  %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]);
    865                                     if ((cErrors % 5) == 4)
    866                                         fprintf(stderr, "\n");
    867                                     cErrors++;
    868                                     if (cErrors > 5 * 10)
    869                                         break;
    870                                 }
    871                             if ((cErrors % 5) != 0)
    872                                 fprintf(stderr, "\n");
    873                         }
    874                     }
    875 
    876                 }
     696                fprintf(stderr, "error: Invalid port number %#lx for %s (valid range 0x010..0x3ff)\n", uTmp, pszArg);
     697                return -1;
    877698            }
    878 
    879             /* restore */
    880             WriteSector(iSector, s_abSaved);
    881         }
    882     }
    883 
    884 
    885     return rc;
    886 }
    887 
     699            if (iWhich == 1)
     700                uBasePort = (uint16_t)uTmp;
     701            else
     702                uCtrlPort = (uint16_t)uTmp;
     703        }
     704        else if (   AtaArgMatchWithValue(pszArg, STR_TUPLE("--port-shift"), cArgs, papszArgs, &iArg, &pszValue)
     705                 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-s"), cArgs, papszArgs, &iArg, &pszValue) )
     706        {
     707            unsigned long uTmp = strtoul(pszValue, NULL, 0);
     708            if (uTmp >= 4)
     709            {
     710                fprintf(stderr, "error: Invalid port shift number %#lx (valid range 0..3)\n", uTmp);
     711                return -1;
     712            }
     713            cShiftPort = (uint8_t)uTmp;
     714        }
     715        else if (   AtaArgMatchWithValue(pszArg, STR_TUPLE("--device"), cArgs, papszArgs, &iArg, &pszValue)
     716                 || AtaArgMatchWithValue(pszArg, STR_TUPLE("-d"), cArgs, papszArgs, &iArg, &pszValue) )
     717        {
     718            unsigned long uTmp = strtoul(pszValue, NULL, 16);
     719            if (   uTmp != ATA_DEV_MASTER
     720                && uTmp != ATA_DEV_SLAVE)
     721            {
     722                fprintf(stderr, "error: Invalid device number %#lx; only %#x (master) or %#x (slave) are allowed.\n",
     723                        uTmp, ATA_DEV_MASTER, ATA_DEV_SLAVE);
     724                return -1;
     725            }
     726            bDevice = (uint8_t)uTmp;
     727        }
     728        else if (   strcmp(pszArg, "--8-bit-data") == 0
     729                 || strcmp(pszArg, "-8") == 0)
     730            f8BitData = 1;
     731        else if (   strcmp(pszArg, "--16-bit-data") == 0
     732                 || strcmp(pszArg, "-16") == 0)
     733            f8BitData = 0;
     734    }
     735
     736    return AtaInit(uBasePort, uCtrlPort, cShiftPort, bDevice, f8BitData);
     737}
     738
  • hacks/xtide/atalib.h

    r72 r73  
    2323
    2424
    25 /*********************************************************************************************************************************
    26 *   Header Files                                                                                                                 *
    27 *********************************************************************************************************************************/
    28 #include <stdarg.h>
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>
     25#ifndef ___atalib_h___
     26#define ___atalib_h___
     27
    3228#include <stdint.h>
    33 #include <io.h>
    34 #include <conio.h>
    35 
    36 /*********************************************************************************************************************************
    37 *   Structures and Typedefs                                                                                                      *
    38 *********************************************************************************************************************************/
    39 typedef struct REGS16
    40 {
    41     uint16_t    ax;     /**<  0 */
    42     uint16_t    cx;     /**<  2 */
    43     uint16_t    dx;     /**<  4 */
    44     uint16_t    si;     /**<  6 */
    45     uint16_t    di;     /**<  8 */
    46     uint16_t    es;     /**< 10 */
    47     uint16_t    efl;    /**< 12 */
    48     uint16_t    ds;     /**< 14 */
    49     uint16_t    bx;     /**< 16 */
    50 } REGS16;
    51 
    52 #define X86_EFL_CF 1
    5329
    5430/* The necessary I/O ports, indexed by "bus". */
    5531#define ATA_PORT_SHIFT      1 /* For XT-CF trick */
    56 #define ATA_REG_DATA(x)             (x)
    57 #define ATA_REG_FEATURES(x)         ((x) + (1 << ATA_PORT_SHIFT))
    58 #define ATA_REG_SECTOR_COUNT(x)     ((x) + (2 << ATA_PORT_SHIFT))
     32#define ATA_REG_DATA(a_uBasePort)           (a_uBasePort)
     33#define ATA_REG_FEATURES(a_uBasePort)       ((a_uBasePort) + (1 << ATA_PORT_SHIFT))
     34#define ATA_REG_SECTOR_COUNT(a_uBasePort)   ((a_uBasePort) + (2 << ATA_PORT_SHIFT))
    5935
    60 #define ATA_REG_SECTOR_NUMBER(x)    ((x) + (3 << ATA_PORT_SHIFT))
    61 #define ATA_REG_CYLINDER_LOW(x)     ((x) + (4 << ATA_PORT_SHIFT))
    62 #define ATA_REG_CYLINDER_HIGH(x)    ((x) + (5 << ATA_PORT_SHIFT))
    63 #define ATA_REG_HEAD(x)             ((x) + (6 << ATA_PORT_SHIFT))
     36#define ATA_REG_SECTOR_NUMBER(a_uBasePort)  ((a_uBasePort) + (3 << ATA_PORT_SHIFT))
     37#define ATA_REG_CYLINDER_LOW(a_uBasePort)   ((a_uBasePort) + (4 << ATA_PORT_SHIFT))
     38#define ATA_REG_CYLINDER_HIGH(a_uBasePort)  ((a_uBasePort) + (5 << ATA_PORT_SHIFT))
     39#define ATA_REG_HEAD(a_uBasePort)           ((a_uBasePort) + (6 << ATA_PORT_SHIFT))
    6440
    65 #define ATA_REG_LBA_0_7(x)          ((x) + (3 << ATA_PORT_SHIFT))
    66 #define ATA_REG_LBA_8_15(x)         ((x) + (4 << ATA_PORT_SHIFT))
    67 #define ATA_REG_LBA_16_23(x)        ((x) + (5 << ATA_PORT_SHIFT))
    68 #define ATA_REG_LBA_24_27_MODE(x)   ((x) + (6 << ATA_PORT_SHIFT))
    69 #define ATA_LBA_MODE                UINT8_C(0x40) /**< Selects LBA mode in ATA_REG_LBA_24_27_MODE. */
     41#define ATA_REG_LBA_0_7(a_uBasePort)        ((a_uBasePort) + (3 << ATA_PORT_SHIFT))
     42#define ATA_REG_LBA_8_15(a_uBasePort)       ((a_uBasePort) + (4 << ATA_PORT_SHIFT))
     43#define ATA_REG_LBA_16_23(a_uBasePort)      ((a_uBasePort) + (5 << ATA_PORT_SHIFT))
     44#define ATA_REG_LBA_24_27_MODE(a_uBasePort) ((a_uBasePort) + (6 << ATA_PORT_SHIFT))
     45#define ATA_LBA_MODE                        UINT8_C(0x40) /**< Selects LBA mode in ATA_REG_LBA_24_27_MODE. */
    7046
    71 #define ATA_REG_DEVICE_SELECT(x)    ((x) + (6 << ATA_PORT_SHIFT))
    72 #define ATA_REG_COMMAND(x)          ((x) + (7 << ATA_PORT_SHIFT))
     47#define ATA_REG_DEVICE_SELECT(a_uBasePort)  ((a_uBasePort) + (6 << ATA_PORT_SHIFT))
     48#define ATA_REG_COMMAND(a_uBasePort)        ((a_uBasePort) + (7 << ATA_PORT_SHIFT))
    7349
    7450
    75 #define ATA_REG_STATUS(x)           ATA_REG_COMMAND(x)
    76 #define ATA_REG_ALT_STATUS(x)       ATA_REG_CONTROL(x)
    77 #define ATA_STS_BUSY                UINT8_C(0x80)
    78 #define ATA_STS_DRDY                UINT8_C(0x40)
    79 #define ATA_STS_DF                  UINT8_C(0x20)
    80 #define ATA_STS_DSC                 UINT8_C(0x10)
    81 #define ATA_STS_DRQ                 UINT8_C(0x08)
    82 #define ATA_STS_CORR                UINT8_C(0x04)
    83 #define ATA_STS_IDX                 UINT8_C(0x02)
    84 #define ATA_STS_ERR                 UINT8_C(0x01)
     51#define ATA_REG_STATUS(a_uBasePort)         ATA_REG_COMMAND(a_uBasePort)
     52#define ATA_REG_ALT_STATUS(a_uCtrlPort)     ATA_REG_CONTROL(a_uCtrlPort)
     53#define ATA_STS_BUSY                        UINT8_C(0x80)
     54#define ATA_STS_DRDY                        UINT8_C(0x40)
     55#define ATA_STS_DF                          UINT8_C(0x20)
     56#define ATA_STS_DSC                         UINT8_C(0x10)
     57#define ATA_STS_DRQ                         UINT8_C(0x08)
     58#define ATA_STS_CORR                        UINT8_C(0x04)
     59#define ATA_STS_IDX                         UINT8_C(0x02)
     60#define ATA_STS_ERR                         UINT8_C(0x01)
    8561
    86 #define ATA_REG_ERROR(x)            ATA_REG_FEATURES(x)
    87 #define ATA_ERR_RSVR                UINT8_C(0x80)
    88 #define ATA_ERR_UNC                 UINT8_C(0x40)
    89 #define ATA_ERR_MC                  UINT8_C(0x20)
    90 #define ATA_ERR_IDNF                UINT8_C(0x10)
    91 #define ATA_ERR_MCR                 UINT8_C(0x08)
    92 #define ATA_ERR_ABRT                UINT8_C(0x04)
    93 #define ATA_ERR_TKNONF              UINT8_C(0x02)
    94 #define ATA_ERR_AMNF                UINT8_C(0x01)
     62#define ATA_REG_ERROR(a_uBasePort)          ATA_REG_FEATURES(a_uBasePort)
     63#define ATA_ERR_RSVR                        UINT8_C(0x80)
     64#define ATA_ERR_UNC                         UINT8_C(0x40)
     65#define ATA_ERR_MC                          UINT8_C(0x20)
     66#define ATA_ERR_IDNF                        UINT8_C(0x10)
     67#define ATA_ERR_MCR                         UINT8_C(0x08)
     68#define ATA_ERR_ABRT                        UINT8_C(0x04)
     69#define ATA_ERR_TKNONF                      UINT8_C(0x02)
     70#define ATA_ERR_AMNF                        UINT8_C(0x01)
    9571
    96 #define ATA_REG_CONTROL(x)          ((x) + (14 << ATA_PORT_SHIFT))
    97 #define ATA_CTL_IEN                 UINT8_C(0x02) /**< Interrupt enable. */
    98 #define ATA_CTL_SRST                UINT8_C(0x04) /**< software reset */
     72#define ATA_REG_CONTROL(a_uCtrlPort)        ((a_uCtrlPort) + (6 << ATA_PORT_SHIFT))
     73#define ATA_CTL_IEN                         UINT8_C(0x02) /**< Interrupt enable. */
     74#define ATA_CTL_SRST                        UINT8_C(0x04) /**< software reset */
    9975
    100 #define ATA_CMD_NOP                 UINT8_C(0x00)
    101 #define ATA_CMD_READ_SECTORS        UINT8_C(0x20)
    102 #define ATA_CMD_READ_SECTORS_NR     UINT8_C(0x21)
    103 #define ATA_CMD_READ_LONG           UINT8_C(0x22)
    104 #define ATA_CMD_READ_LONG_NR        UINT8_C(0x23)
    105 #define ATA_CMD_WRITE_SECTORS       UINT8_C(0x30)
    106 #define ATA_CMD_WRITE_SECTORS_NR    UINT8_C(0x31)
    107 #define ATA_CMD_WRITE_LONG          UINT8_C(0x32)
    108 #define ATA_CMD_WRITE_LONG_NR       UINT8_C(0x33)
    109 #define ATA_CMD_INIT_DEVICE_PARAMS  UINT8_C(0x91)
    110 #define ATA_CMD_SET_FEATURES        UINT8_C(0xef)
    111 #define ATA_CMD_IDENTIFY_DEVICE     UINT8_C(0xec)
     76#define ATA_CMD_NOP                         UINT8_C(0x00)
     77#define ATA_CMD_READ_SECTORS                UINT8_C(0x20)
     78#define ATA_CMD_READ_SECTORS_NR             UINT8_C(0x21)
     79#define ATA_CMD_READ_LONG                   UINT8_C(0x22)
     80#define ATA_CMD_READ_LONG_NR                UINT8_C(0x23)
     81#define ATA_CMD_READ_BUFFER                 UINT8_C(0xe4)
     82#define ATA_CMD_WRITE_SECTORS               UINT8_C(0x30)
     83#define ATA_CMD_WRITE_SECTORS_NR            UINT8_C(0x31)
     84#define ATA_CMD_WRITE_LONG                  UINT8_C(0x32)
     85#define ATA_CMD_WRITE_LONG_NR               UINT8_C(0x33)
     86#define ATA_CMD_WRITE_BUFFER                UINT8_C(0xe8)
     87#define ATA_CMD_INIT_DEVICE_PARAMS          UINT8_C(0x91)
     88#define ATA_CMD_SET_FEATURES                UINT8_C(0xef)
     89#define ATA_CMD_IDENTIFY_DEVICE             UINT8_C(0xec)
    11290
     91#define ATA_DEV_MASTER                      UINT8_C(0x00)  /**< Master device selection bit value. */
     92#define ATA_DEV_SLAVE                       UINT8_C(0x10)  /**< Slave device selection bit value. */
    11393
    114 #define ATA_DEV_MASTER              UINT8_C(0x00)  /**< Master device selection bit value. */
    115 #define ATA_DEV_SLAVE               UINT8_C(0x10)  /**< Slave device selection bit value. */
    116 
    117 #define ATA_FEATURE_EN_8BIT_DATA        UINT8_C(0x01)
    118 #define ATA_FEATURE_DI_8BIT_DATA        UINT8_C(0x81)
    119 #define ATA_FEATURE_EN_WRITE_CACHE      UINT8_C(0x02)
    120 #define ATA_FEATURE_DI_WRITE_CACHE      UINT8_C(0x82)
    121 #define ATA_FEATURE_SET_XFERMODE        UINT8_C(0x03)
     94#define ATA_FEATURE_EN_8BIT_DATA            UINT8_C(0x01)
     95#define ATA_FEATURE_DI_8BIT_DATA            UINT8_C(0x81)
     96#define ATA_FEATURE_EN_WRITE_CACHE          UINT8_C(0x02)
     97#define ATA_FEATURE_DI_WRITE_CACHE          UINT8_C(0x82)
     98#define ATA_FEATURE_SET_XFERMODE            UINT8_C(0x03)
    12299#define ATA_FV_XFERMODE_PIO_MODE_DEFAULT             UINT8_C(0x00)
    123100#define ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY    UINT8_C(0x01)
     
    130107#define ATA_DELAY_400NS()   do { inp(0x21); } while (0)
    131108
     109extern uint16_t g_cHeads;
     110extern uint8_t  g_cSectorsPerTrack;
     111extern uint16_t g_cCylinders;
     112extern uint16_t g_cSectorsPerCylinder;
     113extern uint16_t g_awIdentify[256];
    132114
     115int  AtaInit(uint16_t uBasePort, uint16_t uCtrlPort, uint8_t uPortShift, uint8_t bDevice, uint8_t f8BitData);
     116int  AtaInitFromArgv(int iArg, int cArgs, char **papszArgs);
     117int  AtaReInit(void);
     118int  AtaReset(void);
     119int  AtaIdentifyDevice(uint8_t bDevice, void *pvBuf);
     120int  AtaInitDeviceParams(uint8_t bDevice, uint8_t cSectorsPerTrack, uint8_t cHeads);
     121int  AtaSetFeature(uint8_t bDevice, uint8_t bFeature, uint8_t bValue);
     122int  AtaWriteSector(uint32_t iSector, void const *pvBuf);
     123int  AtaReadSector(uint32_t iSector, void *pvBuf);
     124int  AtaWriteBuffer(void const *pvBuf, uint8_t fExtraChecks);
     125int  AtaReadBuffer(void *pvBuf, uint8_t fExtraChecks);
     126void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData);
     127void AtaReadData(void *pvBuf, size_t cb, uint8_t f8BitData);
    133128
    134 /*********************************************************************************************************************************
    135 *   Global Variables                                                                                                             *
    136 *********************************************************************************************************************************/
    137 uint16_t g_uBasePort   = 0x300;
    138 uint16_t g_uPortShift  = 1;
    139 uint8_t  g_fUseLbaMode = 1;
    140 uint8_t  g_f8BitData   = 1;
    141 uint8_t  g_bDevice     = ATA_DEV_MASTER;
    142 uint8_t  g_bDrv        = 0x80;
     129#endif
    143130
    144 
    145 uint16_t g_cHeads;
    146 uint8_t  g_cSectorsPerTrack;
    147 uint16_t g_cCylinders;
    148 uint16_t g_cSectorsPerCylinder;
    149 
    150 /** The result of the identify command. */
    151 uint16_t g_awIdentify[256];
    152 
    153 
    154 size_t AtaPrintStatus(FILE *pOut, uint8_t bSts)
    155 {
    156     size_t cch = fprintf(pOut, "%#x", bSts);
    157     if (bSts & ATA_STS_BUSY) cch += fprintf(pOut, " busy");
    158     if (bSts & ATA_STS_DRDY) cch += fprintf(pOut, " drdy");
    159     if (bSts & ATA_STS_DF  ) cch += fprintf(pOut, " df");
    160     if (bSts & ATA_STS_DSC ) cch += fprintf(pOut, " dsc");
    161     if (bSts & ATA_STS_DRQ ) cch += fprintf(pOut, " drq");
    162     if (bSts & ATA_STS_CORR) cch += fprintf(pOut, " corr");
    163     if (bSts & ATA_STS_IDX ) cch += fprintf(pOut, " idx");
    164     if (bSts & ATA_STS_ERR ) cch += fprintf(pOut, " err");
    165     return cch;
    166 }
    167 
    168 size_t AtaPrintError(FILE *pOut, uint8_t bErr)
    169 {
    170     size_t cch = fprintf(pOut, "%#x", bErr);
    171     if (bErr & ATA_ERR_RSVR  ) cch += fprintf(pOut, " rsrv");
    172     if (bErr & ATA_ERR_UNC   ) cch += fprintf(pOut, " unc");
    173     if (bErr & ATA_ERR_MC    ) cch += fprintf(pOut, " mc");
    174     if (bErr & ATA_ERR_IDNF  ) cch += fprintf(pOut, " idnf");
    175     if (bErr & ATA_ERR_MCR   ) cch += fprintf(pOut, " mcr");
    176     if (bErr & ATA_ERR_ABRT  ) cch += fprintf(pOut, " abrt");
    177     if (bErr & ATA_ERR_TKNONF) cch += fprintf(pOut, " tknonf");
    178     if (bErr & ATA_ERR_AMNF  ) cch += fprintf(pOut, " amnf");
    179     return cch;
    180 }
    181 
    182 static int AtaError(uint8_t bSts, const char *pszFormat, ...)
    183 {
    184     va_list va;
    185 
    186     fprintf(stderr, "error: ");
    187     va_start(va, pszFormat);
    188     vfprintf(stderr, pszFormat, va);
    189     va_end(va);
    190 
    191     fprintf(stderr, "\n status=");
    192     AtaPrintStatus(stderr, bSts);
    193     fprintf(stderr, "\n  error= ");
    194     AtaPrintError(stderr, inp(ATA_REG_ERROR(g_uBasePort)));
    195     fprintf(stderr, "\n");
    196 
    197     return -1;
    198 }
    199 
    200 uint8_t AtaWaitBusy(void)
    201 {
    202     uint32_t cLoops = 0;
    203     uint8_t  bStatus;
    204     do
    205     {
    206         if ((++cLoops & 0xfffff) == 0)
    207             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
    208         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
    209     } while ((bStatus & (ATA_STS_BUSY | ATA_STS_ERR)) == ATA_STS_BUSY);
    210     return bStatus;
    211 }
    212 
    213 uint8_t AtaWaitBusyDeviceReady(void)
    214 {
    215     uint32_t cLoops = 0;
    216     uint8_t bStatus;
    217     do
    218     {
    219         if ((++cLoops & 0xfffff) == 0)
    220             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
    221         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
    222     } while (    (bStatus & (ATA_STS_BUSY | ATA_STS_DRDY)) != ATA_STS_DRDY
    223              && !(bStatus & ATA_STS_ERR) );
    224     return bStatus;
    225 }
    226 
    227 uint8_t AtaWaitBusyForData(void)
    228 {
    229     uint32_t cLoops = 0;
    230     uint8_t bStatus;
    231     do
    232     {
    233         if ((++cLoops & 0xfffff) == 0)
    234             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
    235         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
    236     } while (    (bStatus & (ATA_STS_BUSY | ATA_STS_DRQ)) != ATA_STS_DRQ
    237              && !(bStatus & ATA_STS_ERR) );
    238     return bStatus;
    239 }
    240 
    241 uint8_t AtaSubmitCommandAndWait(uint8_t bCommand)
    242 {
    243 
    244     outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
    245     ATA_DELAY_400NS();
    246     return AtaWaitBusy();
    247 }
    248 
    249 uint8_t AtaSubmitCommandAndWaitForData(uint8_t bCommand)
    250 {
    251 
    252     outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
    253     ATA_DELAY_400NS();
    254     return AtaWaitBusyForData();
    255 }
    256 
    257 uint8_t AtaSelectDevice(uint8_t bDevice)
    258 {
    259     outp(ATA_REG_DEVICE_SELECT(g_uBasePort), g_bDevice);
    260     ATA_DELAY_400NS();
    261     return AtaWaitBusyDeviceReady();
    262 }
    263 
    264 void AtaSetSectorAddress(uint32_t iSector, uint8_t bDevice)
    265 {
    266     if (g_fUseLbaMode)
    267     {
    268         outp(ATA_REG_LBA_0_7(g_uBasePort), iSector & 0xff);
    269         outp(ATA_REG_LBA_8_15(g_uBasePort), (iSector >> 8) & 0xff);
    270         outp(ATA_REG_LBA_16_23(g_uBasePort), (iSector >> 16) & 0xff);
    271         outp(ATA_REG_LBA_24_27_MODE(g_uBasePort), ((iSector >> 24) & 0x0f) | ATA_LBA_MODE | bDevice);
    272     }
    273     else
    274     {
    275         uint16_t iCyl = iSector / g_cSectorsPerCylinder;
    276         uint16_t iRem = iSector % g_cSectorsPerCylinder;
    277         uint8_t  iHd  = iRem / g_cSectorsPerTrack;
    278         uint8_t  iSec = iRem % g_cSectorsPerTrack;
    279 
    280         outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), iSec);
    281         outp(ATA_REG_CYLINDER_LOW(g_uBasePort), iCyl & 0xff);
    282         outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), iCyl >> 8);
    283         outp(ATA_REG_HEAD(g_uBasePort), iHd | bDevice);
    284     }
    285 }
    286 
    287 void AtaReadData(void *pvBuf, size_t cb, uint8_t f8BitData)
    288 {
    289     uint16_t  uDataPort = ATA_REG_DATA(g_uBasePort);
    290     uint16_t *pu16      = (uint16_t *)pvBuf;
    291     cb >>= 1;
    292 
    293     if (f8BitData)
    294     {
    295         while (cb-- > 0)
    296         {
    297             uint8_t b1 = inp(uDataPort);
    298             uint8_t b2 = inp(uDataPort);
    299             *pu16++ = b1 | ((uint16_t)b2 << 8);
    300         }
    301     }
    302     else
    303     {
    304         while (cb-- > 0)
    305             *pu16++ = inpw(uDataPort);
    306     }
    307 }
    308 
    309 ////static uint8_t AtaWaitForDataRequest(size_t cbLeft)
    310 ////{
    311 ////    uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    312 ////    uint8_t  bStsFirst = inp(uAltStsPort);
    313 ////    uint8_t  bSts = bStsFirst;
    314 ////    uint32_t cLoops = 0;
    315 ////    do
    316 ////    {
    317 ////        if (++cLoops & 0xffff)
    318 ////        {
    319 ////static unsigned x = 0;
    320 ////if (x < 16)
    321 ////{
    322 ////    printf("AtaWaitForDataRequest: bFirst=%#x bLast=%#x cbLeft=%#x\n", bStsFirst, bSts, cbLeft);
    323 ////    x++;
    324 ////}
    325 ////            break;
    326 ////        }
    327 ////        bSts = inp(uAltStsPort);
    328 ////    } while (!(bSts & (ATA_STS_DRQ | ATA_STS_ERR)));
    329 ////    return bSts;
    330 ////}
    331 
    332 void xchg(uint8_t volatile *pb);
    333 #pragma aux xchg = \
    334     "xchg [si], cx" \
    335     "xchg [si], cx" \
    336     "xchg [si], cx" \
    337     "xchg [si], cx" \
    338     parm [si] \
    339     modify exact [cx];
    340 
    341 void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
    342 {
    343 //    uint16_t        uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    344     uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
    345 
    346     if (f8BitData)
    347     {
    348 #if 0
    349         uint8_t const   * volatile pbSrc = (uint8_t const *)pvBuf;
    350         uint8_t volatile ab[64];
    351         uint8_t volatile *pb = &ab[0];
    352         while (((uintptr_t)pb & 0x1f) != 0x1f)
    353             pb++;
    354         //uint8_t  bSts1, bSts2;
    355 inp(0x21);
    356 xchg(pb);
    357 
    358         while (cb-- > 0)
    359         {
    360             uint8_t b = *pbSrc++;
    361             xchg(pb);
    362             outp(uDataPort, b);
    363             xchg(pb);
    364             b = *pbSrc++;
    365             xchg(pb);
    366 //inp(0x21);
    367             outp(uDataPort, b);
    368             xchg(pb);
    369 //inp(0x21);
    370             //if (cb < 30)
    371             //{
    372             //    if ((cb & 3) == 3)
    373             //        printf("bSts1=%#x bSts2=%#x ", bSts1, bSts2);
    374             //    else
    375             //        printf("bSts1=%#x bSts2=%#x\n", bSts1, bSts2);
    376             //}
    377         }
    378 inp(0x21);
    379 #else
    380         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    381         cb >>= 1;
    382         while (cb-- > 0)
    383         {
    384             uint16_t register u16 = *pu16++;
    385             outp(uDataPort, (uint8_t)u16);
    386             outp(uDataPort, (uint8_t)(u16 >> 8));
    387         }
    388 #endif
    389     }
    390     else
    391     {
    392         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    393         cb >>= 1;
    394         while (cb-- > 0)
    395             outp(uDataPort, *pu16++);
    396     }
    397 }
    398 
    399 int AtaReadSector(uint32_t iSector, void *pvBuf)
    400 {
    401     uint8_t bSts = AtaWaitBusy();
    402     if (bSts & ATA_STS_ERR)
    403         return AtaError(bSts, "Prepping for reading sector %lu", iSector);
    404 
    405 printf("AtaReadSector #2\n");
    406     bSts = AtaSelectDevice(g_bDevice);
    407     if (bSts & ATA_STS_ERR)
    408         return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
    409 
    410 //printf("AtaReadSector #3\n");
    411     outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
    412     outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
    413     AtaSetSectorAddress(iSector, g_bDevice);
    414 
    415 //printf("AtaReadSector #4\n");
    416     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
    417     if (bSts & ATA_STS_ERR)
    418         return AtaError(bSts, "Reading sector %lu", iSector);
    419 
    420     if (!(bSts & ATA_STS_DRQ))
    421         return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
    422 
    423 
    424 //printf("AtaReadSector #5\n");
    425     AtaReadData(pvBuf, 512, g_f8BitData);
    426 //printf("AtaReadSector #6: bSts=%#x\n", inp(ATA_REG_ALT_STATUS(g_uBasePort)));
    427     bSts = inp(ATA_REG_STATUS(g_uBasePort));
    428     if ((bSts & ATA_STS_DRQ))
    429         return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
    430     if ((bSts & ATA_STS_ERR))
    431         return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
    432     return 0;
    433 }
    434 
    435 int AtaWriteSector(uint32_t iSector, void const *pvBuf)
    436 {
    437 //int x = printf("AtaWriteSector #1\n");
    438     uint8_t bSts = AtaWaitBusy();
    439     if (bSts & ATA_STS_ERR)
    440         return AtaError(bSts, "Prepping for writing sector %lu", iSector);
    441 printf("AtaWriteSector #2\n");
    442 
    443     bSts = AtaSelectDevice(g_bDevice);
    444     if (bSts & ATA_STS_ERR)
    445         return AtaError(bSts, "Selecting device for writing sector %lu", iSector);
    446 
    447     outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
    448     outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
    449     AtaSetSectorAddress(iSector, g_bDevice);
    450 
    451 //printf("AtaWriteSector #3\n");
    452     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
    453     if (bSts & ATA_STS_ERR)
    454         return AtaError(bSts, "writing sector (#1) %lu", iSector);
    455     if (!(bSts & ATA_STS_DRQ))
    456         return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
    457 
    458 //printf("AtaWriteSector #4\n");
    459     AtaWriteData(pvBuf, 512, g_f8BitData);
    460 //printf("AtaWriteSector #5\n");
    461     ATA_DELAY_400NS();
    462     bSts = AtaWaitBusy();
    463 //printf("AtaWriteSector #6\n");
    464     if (bSts & ATA_STS_ERR)
    465         return AtaError(bSts, "writing sector (#2) %lu", iSector);
    466     if (bSts & ATA_STS_DRQ)
    467         return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
    468 
    469     return 0;
    470 }
    471 
    472 int AtaIdentifyDevice(uint8_t bDevice, void *pvBuf)
    473 {
    474     uint8_t bSts = AtaWaitBusy();
    475     if (bSts & ATA_STS_ERR)
    476         return AtaError(bSts, "Prepping for device %#x identification", bDevice);
    477 
    478     bSts = AtaSelectDevice(g_bDevice);
    479     if (bSts & ATA_STS_ERR)
    480         return AtaError(bSts, "Selecting device %#x for identification", bDevice);
    481 
    482     outp(ATA_REG_FEATURES(g_uBasePort),         0);
    483     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     0);
    484     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
    485     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
    486     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
    487     //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
    488 
    489     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_IDENTIFY_DEVICE);
    490     if (bSts & ATA_STS_ERR)
    491         return AtaError(bSts, "Device %#x identification", bDevice);
    492     if (!(bSts & ATA_STS_DRQ))
    493         return AtaError(bSts, "DRQ not set after device %#x identification", bDevice);
    494 
    495     AtaReadData(pvBuf, 512, g_f8BitData);
    496     return 0;
    497 }
    498 
    499 int AtaSetFeature(uint8_t bDevice, uint8_t bFeature, uint8_t bValue)
    500 {
    501     uint8_t bSts = AtaWaitBusy();
    502     if (bSts & ATA_STS_ERR)
    503         return AtaError(bSts, "Prepping for setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
    504 
    505     bSts = AtaSelectDevice(g_bDevice);
    506     if (bSts & ATA_STS_ERR)
    507         return AtaError(bSts, "Selecting device %#x for setting feature %#x (%#x)", bDevice, bFeature, bValue);
    508 
    509     outp(ATA_REG_FEATURES(g_uBasePort),         bFeature);
    510     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     0);
    511     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    bValue);
    512     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
    513     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
    514     //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
    515 
    516     bSts = AtaSubmitCommandAndWait(ATA_CMD_SET_FEATURES);
    517     if (bSts & ATA_STS_ERR)
    518         return AtaError(bSts, "Setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
    519     if (bSts & ATA_STS_DRQ)
    520         return AtaError(bSts, "DRQ is set after setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
    521     return 0;
    522 }
    523 
    524 int AtaInitDeviceParams(uint8_t bDevice, uint8_t cSectorsPerTrack, uint8_t cHeads)
    525 {
    526     uint8_t bSts = AtaWaitBusy();
    527     if (bSts & ATA_STS_ERR)
    528         return AtaError(bSts, "Prepping for device %#x parameter initialization", bDevice);
    529 
    530     bSts = AtaSelectDevice(g_bDevice);
    531     if (bSts & ATA_STS_ERR)
    532         return AtaError(bSts, "Selecting device for device %#x parameter initialization", bDevice);
    533 
    534     outp(ATA_REG_FEATURES(g_uBasePort),         0);
    535     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     cSectorsPerTrack);
    536     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
    537     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
    538     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
    539     outp(ATA_REG_HEAD(g_uBasePort), g_bDevice | cHeads);
    540 
    541     bSts = AtaSubmitCommandAndWait(ATA_CMD_INIT_DEVICE_PARAMS);
    542     if (bSts & ATA_STS_ERR)
    543         return AtaError(bSts, "Device %#x parameter initialization", bDevice);
    544     if (bSts & ATA_STS_DRQ)
    545         return AtaError(bSts, "DRQ is set after device %#x parameter initialization", bDevice);
    546     return 0;
    547 }
    548 
    549 int AtaReset(void)
    550 {
    551     uint8_t bSts;
    552 
    553     /* Set the reset flat. */
    554     outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_SRST);
    555 
    556     /* Wait for the busy flag response. */
    557     ATA_DELAY_400NS();
    558     ATA_DELAY_400NS();
    559     while (!(bSts = inp(ATA_REG_STATUS(g_uBasePort))) & ATA_STS_BUSY)
    560         ATA_DELAY_400NS();
    561 
    562     /* Clear the reset flag. */
    563     outp(ATA_REG_CONTROL(g_uBasePort), 0);
    564     ATA_DELAY_400NS();
    565 
    566     /* Wait for the controller to become non-busy. */
    567     bSts = AtaWaitBusy();
    568     if (bSts & ATA_STS_ERR)
    569         return AtaError(bSts, "Software reset failed");
    570     return 0;
    571 }
    572 
    573 
    574 int AtaInit(void)
    575 {
    576     uint8_t bSts = inp(ATA_REG_ALT_STATUS(g_uBasePort));
    577     printf("alt status=");
    578     AtaPrintStatus(stdout, bSts);
    579     printf("\n");
    580 
    581     bSts = inp(ATA_REG_STATUS(g_uBasePort));
    582     printf("    status=");
    583     AtaPrintStatus(stdout, bSts);
    584     printf("\n");
    585 
    586     if (AtaReset() != 0)
    587         return -1;
    588 
    589     /* Enable 8-bit data transfers (just to be on the safe side). */
    590     AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
    591 
    592     /* Identify the device. */
    593     memset(g_awIdentify, 0, sizeof(g_awIdentify));
    594     if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
    595         return -1;
    596 
    597     /** @todo this is rather simple... */
    598     g_cCylinders = g_awIdentify[1];
    599     g_cHeads     = g_awIdentify[3];
    600     g_cSectorsPerTrack = g_awIdentify[6];
    601     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    602     printf("Device %#x parameters: %u cylinders, %u heads, %u sectors\n",
    603            g_bDevice, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    604 
    605     /* Disable stuff and try select pio modes. */
    606     AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
    607     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
    608     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG | 0);
    609 
    610     return 0;
    611 }
    612 
    613 
    614 
    615 
    616 /*
    617  * INT13h access methods
    618  * INT13h access methods
    619  * INT13h access methods
    620  */
    621 
    622 void BiosCall13(REGS16 *pRegs);
    623 #pragma aux BiosCall13 = \
    624     "push   ax" \
    625     "push   cx" \
    626     "push   dx" \
    627     "push   bp" \
    628     "push   si" \
    629     "push   di" \
    630     "push   es" \
    631     "push   bx" \
    632     "push   ds" \
    633     \
    634     "mov    ax,  [bx]" \
    635     "mov    cx,  [bx +  2]" \
    636     "mov    dx,  [bx +  4]" \
    637     "mov    si,  [bx +  6]" \
    638     "mov    di,  [bx +  8]" \
    639     "mov    es,  [bx + 10]" \
    640     "push   word ptr [bx + 12]" \
    641     "popf" \
    642     "push   word ptr [bx + 14]" \
    643     "push   word ptr [bx + 16]" \
    644     "pop    bx" \
    645     "pop    ds" \
    646     \
    647     "int    13h"\
    648     \
    649     "push   ds" \
    650     "push   bx" \
    651     "mov    bp, sp" \
    652     "mov    ds, [bp + 4]" \
    653     "mov    bx, [bp + 6]" \
    654     "mov    [bx], ax" \
    655     "mov    [bx +  2], cx" \
    656     "mov    [bx +  4], dx" \
    657     "mov    [bx +  6], si" \
    658     "mov    [bx +  8], di" \
    659     "mov    [bx + 10], es" \
    660     "pushf" \
    661     "pop    ax" \
    662     "mov    [bx + 12], ax" \
    663     "pop    ax" \
    664     "mov    [bx + 14], ax" \
    665     "pop    ax" \
    666     "mov    [bx + 16], ax" \
    667     \
    668     "pop    ds" \
    669     "pop    bx" \
    670     "pop    es" \
    671     "pop    di" \
    672     "pop    si" \
    673     "pop    bp" \
    674     "pop    dx" \
    675     "pop    cx" \
    676     "pop    ax" \
    677     parm [bx];
    678 
    679 
    680 int Int13hInit(void)
    681 {
    682     REGS16 Regs;
    683     memset(&Regs, 0, sizeof(Regs));
    684     Regs.ax = 0x0800;
    685     Regs.dx = g_bDrv;
    686     BiosCall13(&Regs);
    687     /** @todo check for errors.   */
    688     g_cHeads = (Regs.dx >> 8) + 1;
    689     g_cSectorsPerTrack = Regs.cx & 0x3f;
    690     g_cCylinders = (Regs.cx >> 8) | ((Regs.cx & 0xc0) << 2);
    691     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    692 
    693     printf("Drive %#x parameters: %u cylinders, %u heads, %u sectors\n",
    694            g_bDrv, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    695     if (!(Regs.efl & X86_EFL_CF))
    696         return 0;
    697     fprintf(stderr, "Error getting disk params: %#x\n", Regs.ax);
    698     return -1;
    699 }
    700 
    701 void SectorNoToInt13(uint32_t iSector, REGS16 *pRegs)
    702 {
    703     uint16_t iRem = iSector % g_cSectorsPerCylinder;
    704     uint16_t iCyl = iSector / g_cSectorsPerCylinder;
    705     pRegs->cx  = iCyl << 8;
    706     pRegs->cx |= (iCyl >> 2) & 0xc0;
    707     pRegs->cx |= (iRem % g_cSectorsPerTrack) & 0x3f;
    708     pRegs->dx &= UINT16_C(0x00ff);
    709     pRegs->dx |= (iRem / g_cSectorsPerTrack) << 8;
    710 }
    711 
    712 int Int13hReadSector(uint32_t iSector, void *pvBuf)
    713 {
    714     REGS16   Regs;
    715     memset(&Regs, 0, sizeof(Regs));
    716     Regs.ax = 0x0201;
    717     Regs.dx = g_bDrv;
    718     Regs.bx = (unsigned)(void __near *)pvBuf;
    719     Regs.es = (__segment)pvBuf;
    720     SectorNoToInt13(iSector, &Regs);
    721     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
    722     BiosCall13(&Regs);
    723     if (!(Regs.efl & X86_EFL_CF))
    724         return 0;
    725     fprintf(stderr, "Error reading sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
    726     return -1;
    727 }
    728 
    729 int Int13hWriteSector(uint32_t iSector, void const *pvBuf)
    730 {
    731     REGS16   Regs;
    732     memset(&Regs, 0, sizeof(Regs));
    733     Regs.ax = 0x0301;
    734     Regs.dx = g_bDrv;
    735     Regs.bx = (unsigned)(void const __near *)pvBuf;
    736     Regs.es = (__segment)pvBuf;
    737     SectorNoToInt13(iSector, &Regs);
    738     printf("ax=%#x dx=%#x cx=%#x es:bx=%04x:%04x\n", Regs.ax, Regs.dx, Regs.cx, Regs.es, Regs.bx);
    739     BiosCall13(&Regs);
    740     if (!(Regs.efl & X86_EFL_CF))
    741         return 0;
    742     fprintf(stderr, "Error writing sector %lu on %#x: %#x\n", iSector, g_bDrv, Regs.ax);
    743     return -1;
    744 }
    745 
    746 
    747 
    748 int GetDriveParams(void)
    749 {
    750 #ifdef USE_INT13H
    751     return Int13hInit();
    752 #else
    753     return AtaInit();
    754 #endif
    755 }
    756 
    757 int ReadSector(uint32_t iSector, void *pvBuf)
    758 {
    759 #ifdef USE_INT13H
    760     return Int13hReadSector(iSector, pvBuf);
    761 #else
    762     return AtaReadSector(iSector, pvBuf);
    763 #endif
    764 }
    765 
    766 int WriteSector(uint32_t iSector, void const *pvBuf)
    767 {
    768 #ifdef USE_INT13H
    769     return Int13hWriteSector(iSector, pvBuf);
    770 #else
    771     return AtaWriteSector(iSector, pvBuf);
    772 #endif
    773 }
    774 
    775 
    776 
    777 
    778 static int usage(void)
    779 {
    780     printf("usage: writetst [sector] [drv]\n");
    781     return 1;
    782 }
    783 
    784 
    785 int main(int argc, char **argv)
    786 {
    787     int rc = 1;
    788 
    789     /*
    790      * Parse parameters.
    791      */
    792     uint32_t iSector = 3;
    793     g_bDrv = 0x80;
    794     g_bDevice = ATA_DEV_MASTER;
    795 
    796     if (argc > 3)
    797     {
    798         fprintf(stderr, "too many parameters!\n");
    799         return usage();
    800     }
    801     if (argc > 1)
    802     {
    803         iSector = strtoul(argv[1], NULL, 0);
    804         if (   iSector == 0
    805             || (iSector >= 32 && iSector < 65535)
    806             || iSector > 0x800000 /*4G*/)
    807         {
    808             fprintf(stderr, "error: start sector is out of bounds: %s (%lu)\n", argv[1], iSector);
    809             return usage();
    810         }
    811     }
    812     if (argc > 2)
    813     {
    814         unsigned long uTmp = strtoul(argv[2], NULL, 0);
    815         if (uTmp < 0x80 || uTmp > 0x8f)
    816         {
    817             fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp);
    818             return usage();
    819         }
    820         g_bDrv = (uint8_t)uTmp;
    821         g_bDevice = g_bDrv == 0x80 ? ATA_DEV_MASTER : ATA_DEV_SLAVE; /* simplified */
    822     }
    823 
    824     /*
    825      * Detect drive parameters.
    826      */
    827     if (GetDriveParams() == 0)
    828     {
    829         static uint8_t s_abSaved[512];
    830         if (ReadSector(iSector, s_abSaved) == 0)
    831         {
    832             static uint8_t s_abWrite[512];
    833             unsigned i;
    834             unsigned cTries;
    835             //unsigned cMaxTries = 20;
    836             unsigned cMaxTries = 1;
    837 
    838             for (i = 0; i < 512; i++)
    839                 s_abWrite[i] = (uint8_t)i;
    840 
    841             for (cTries = 0; cTries < cMaxTries && rc != 0; cTries++)
    842             {
    843                 if (WriteSector(iSector, s_abWrite) == 0)
    844                 {
    845                     static uint8_t s_abReadBack[512];
    846 
    847                     if (ReadSector(iSector, s_abReadBack) == 0)
    848                     {
    849                         for (i = 0; i < 512; i++)
    850                             s_abWrite[i] = (uint8_t)i;
    851 
    852                         if (memcmp(s_abReadBack, s_abWrite, sizeof(s_abReadBack)) == 0)
    853                         {
    854                             rc = 0;
    855                             printf("wrote sector and successfully read it back\n");
    856                         }
    857                         else if (cTries >= cMaxTries - 1)
    858                         {
    859                             unsigned cErrors = 0;
    860                             fprintf(stderr, "read back doesn't match what was written:\n");
    861                             for (i = 0; i < 512; i++)
    862                                 if (s_abReadBack[i] != (uint8_t)i)
    863                                 {
    864                                     fprintf(stderr,  "  %03x: %02x->%02x", i, (uint8_t)i, s_abReadBack[i]);
    865                                     if ((cErrors % 5) == 4)
    866                                         fprintf(stderr, "\n");
    867                                     cErrors++;
    868                                     if (cErrors > 5 * 10)
    869                                         break;
    870                                 }
    871                             if ((cErrors % 5) != 0)
    872                                 fprintf(stderr, "\n");
    873                         }
    874                     }
    875 
    876                 }
    877             }
    878 
    879             /* restore */
    880             WriteSector(iSector, s_abSaved);
    881         }
    882     }
    883 
    884 
    885     return rc;
    886 }
    887 
  • hacks/xtide/writeatatest.c

    r72 r73  
    3333#include <io.h>
    3434#include <conio.h>
     35#include "atalib.h"
     36
    3537
    3638/*********************************************************************************************************************************
     
    5254#define X86_EFL_CF 1
    5355
    54 /* The necessary I/O ports, indexed by "bus". */
    55 #define ATA_PORT_SHIFT      1 /* For XT-CF trick */
    56 #define ATA_REG_DATA(x)             (x)
    57 #define ATA_REG_FEATURES(x)         ((x) + (1 << ATA_PORT_SHIFT))
    58 #define ATA_REG_SECTOR_COUNT(x)     ((x) + (2 << ATA_PORT_SHIFT))
    59 
    60 #define ATA_REG_SECTOR_NUMBER(x)    ((x) + (3 << ATA_PORT_SHIFT))
    61 #define ATA_REG_CYLINDER_LOW(x)     ((x) + (4 << ATA_PORT_SHIFT))
    62 #define ATA_REG_CYLINDER_HIGH(x)    ((x) + (5 << ATA_PORT_SHIFT))
    63 #define ATA_REG_HEAD(x)             ((x) + (6 << ATA_PORT_SHIFT))
    64 
    65 #define ATA_REG_LBA_0_7(x)          ((x) + (3 << ATA_PORT_SHIFT))
    66 #define ATA_REG_LBA_8_15(x)         ((x) + (4 << ATA_PORT_SHIFT))
    67 #define ATA_REG_LBA_16_23(x)        ((x) + (5 << ATA_PORT_SHIFT))
    68 #define ATA_REG_LBA_24_27_MODE(x)   ((x) + (6 << ATA_PORT_SHIFT))
    69 #define ATA_LBA_MODE                UINT8_C(0x40) /**< Selects LBA mode in ATA_REG_LBA_24_27_MODE. */
    70 
    71 #define ATA_REG_DEVICE_SELECT(x)    ((x) + (6 << ATA_PORT_SHIFT))
    72 #define ATA_REG_COMMAND(x)          ((x) + (7 << ATA_PORT_SHIFT))
    73 
    74 
    75 #define ATA_REG_STATUS(x)           ATA_REG_COMMAND(x)
    76 #define ATA_REG_ALT_STATUS(x)       ATA_REG_CONTROL(x)
    77 #define ATA_STS_BUSY                UINT8_C(0x80)
    78 #define ATA_STS_DRDY                UINT8_C(0x40)
    79 #define ATA_STS_DF                  UINT8_C(0x20)
    80 #define ATA_STS_DSC                 UINT8_C(0x10)
    81 #define ATA_STS_DRQ                 UINT8_C(0x08)
    82 #define ATA_STS_CORR                UINT8_C(0x04)
    83 #define ATA_STS_IDX                 UINT8_C(0x02)
    84 #define ATA_STS_ERR                 UINT8_C(0x01)
    85 
    86 #define ATA_REG_ERROR(x)            ATA_REG_FEATURES(x)
    87 #define ATA_ERR_RSVR                UINT8_C(0x80)
    88 #define ATA_ERR_UNC                 UINT8_C(0x40)
    89 #define ATA_ERR_MC                  UINT8_C(0x20)
    90 #define ATA_ERR_IDNF                UINT8_C(0x10)
    91 #define ATA_ERR_MCR                 UINT8_C(0x08)
    92 #define ATA_ERR_ABRT                UINT8_C(0x04)
    93 #define ATA_ERR_TKNONF              UINT8_C(0x02)
    94 #define ATA_ERR_AMNF                UINT8_C(0x01)
    95 
    96 #define ATA_REG_CONTROL(x)          ((x) + (14 << ATA_PORT_SHIFT))
    97 #define ATA_CTL_IEN                 UINT8_C(0x02) /**< Interrupt enable. */
    98 #define ATA_CTL_SRST                UINT8_C(0x04) /**< software reset */
    99 
    100 #define ATA_CMD_NOP                 UINT8_C(0x00)
    101 #define ATA_CMD_READ_SECTORS        UINT8_C(0x20)
    102 #define ATA_CMD_READ_SECTORS_NR     UINT8_C(0x21)
    103 #define ATA_CMD_READ_LONG           UINT8_C(0x22)
    104 #define ATA_CMD_READ_LONG_NR        UINT8_C(0x23)
    105 #define ATA_CMD_WRITE_SECTORS       UINT8_C(0x30)
    106 #define ATA_CMD_WRITE_SECTORS_NR    UINT8_C(0x31)
    107 #define ATA_CMD_WRITE_LONG          UINT8_C(0x32)
    108 #define ATA_CMD_WRITE_LONG_NR       UINT8_C(0x33)
    109 #define ATA_CMD_INIT_DEVICE_PARAMS  UINT8_C(0x91)
    110 #define ATA_CMD_SET_FEATURES        UINT8_C(0xef)
    111 #define ATA_CMD_IDENTIFY_DEVICE     UINT8_C(0xec)
    112 
    113 
    114 #define ATA_DEV_MASTER              UINT8_C(0x00)  /**< Master device selection bit value. */
    115 #define ATA_DEV_SLAVE               UINT8_C(0x10)  /**< Slave device selection bit value. */
    116 
    117 #define ATA_FEATURE_EN_8BIT_DATA        UINT8_C(0x01)
    118 #define ATA_FEATURE_DI_8BIT_DATA        UINT8_C(0x81)
    119 #define ATA_FEATURE_EN_WRITE_CACHE      UINT8_C(0x02)
    120 #define ATA_FEATURE_DI_WRITE_CACHE      UINT8_C(0x82)
    121 #define ATA_FEATURE_SET_XFERMODE        UINT8_C(0x03)
    122 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT             UINT8_C(0x00)
    123 #define ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY    UINT8_C(0x01)
    124 #define ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG            UINT8_C(0x08)
    125 #define ATA_FV_XFERMODE_SWDMA_MODE_XXX_FLAG          UINT8_C(0x10)
    126 #define ATA_FV_XFERMODE_MWDMA_MODE_XXX_FLAG          UINT8_C(0x20)
    127 
    128 /** Delay a bit by reading PIC mask. Should take 4-5 bus cycles,
    129  * and thus be more than the required 400ns delay on old computers. */
    130 #define ATA_DELAY_400NS()   do { inp(0x21); } while (0)
    131 
    132 
    13356
    13457/*********************************************************************************************************************************
    13558*   Global Variables                                                                                                             *
    13659*********************************************************************************************************************************/
    137 uint16_t g_uBasePort   = 0x300;
    138 uint16_t g_uPortShift  = 1;
    139 uint8_t  g_fUseLbaMode = 1;
    140 uint8_t  g_f8BitData   = 1;
    141 uint8_t  g_bDevice     = ATA_DEV_MASTER;
    14260uint8_t  g_bDrv        = 0x80;
    143 
    144 
    145 uint16_t g_cHeads;
    146 uint8_t  g_cSectorsPerTrack;
    147 uint16_t g_cCylinders;
    148 uint16_t g_cSectorsPerCylinder;
    149 
    150 /** The result of the identify command. */
    151 uint16_t g_awIdentify[256];
    152 
    153 
    154 size_t AtaPrintStatus(FILE *pOut, uint8_t bSts)
    155 {
    156     size_t cch = fprintf(pOut, "%#x", bSts);
    157     if (bSts & ATA_STS_BUSY) cch += fprintf(pOut, " busy");
    158     if (bSts & ATA_STS_DRDY) cch += fprintf(pOut, " drdy");
    159     if (bSts & ATA_STS_DF  ) cch += fprintf(pOut, " df");
    160     if (bSts & ATA_STS_DSC ) cch += fprintf(pOut, " dsc");
    161     if (bSts & ATA_STS_DRQ ) cch += fprintf(pOut, " drq");
    162     if (bSts & ATA_STS_CORR) cch += fprintf(pOut, " corr");
    163     if (bSts & ATA_STS_IDX ) cch += fprintf(pOut, " idx");
    164     if (bSts & ATA_STS_ERR ) cch += fprintf(pOut, " err");
    165     return cch;
    166 }
    167 
    168 size_t AtaPrintError(FILE *pOut, uint8_t bErr)
    169 {
    170     size_t cch = fprintf(pOut, "%#x", bErr);
    171     if (bErr & ATA_ERR_RSVR  ) cch += fprintf(pOut, " rsrv");
    172     if (bErr & ATA_ERR_UNC   ) cch += fprintf(pOut, " unc");
    173     if (bErr & ATA_ERR_MC    ) cch += fprintf(pOut, " mc");
    174     if (bErr & ATA_ERR_IDNF  ) cch += fprintf(pOut, " idnf");
    175     if (bErr & ATA_ERR_MCR   ) cch += fprintf(pOut, " mcr");
    176     if (bErr & ATA_ERR_ABRT  ) cch += fprintf(pOut, " abrt");
    177     if (bErr & ATA_ERR_TKNONF) cch += fprintf(pOut, " tknonf");
    178     if (bErr & ATA_ERR_AMNF  ) cch += fprintf(pOut, " amnf");
    179     return cch;
    180 }
    181 
    182 static int AtaError(uint8_t bSts, const char *pszFormat, ...)
    183 {
    184     va_list va;
    185 
    186     fprintf(stderr, "error: ");
    187     va_start(va, pszFormat);
    188     vfprintf(stderr, pszFormat, va);
    189     va_end(va);
    190 
    191     fprintf(stderr, "\n status=");
    192     AtaPrintStatus(stderr, bSts);
    193     fprintf(stderr, "\n  error= ");
    194     AtaPrintError(stderr, inp(ATA_REG_ERROR(g_uBasePort)));
    195     fprintf(stderr, "\n");
    196 
    197     return -1;
    198 }
    199 
    200 uint8_t AtaWaitBusy(void)
    201 {
    202     uint32_t cLoops = 0;
    203     uint8_t  bStatus;
    204     do
    205     {
    206         if ((++cLoops & 0xfffff) == 0)
    207             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
    208         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
    209     } while ((bStatus & (ATA_STS_BUSY | ATA_STS_ERR)) == ATA_STS_BUSY);
    210     return bStatus;
    211 }
    212 
    213 uint8_t AtaWaitBusyDeviceReady(void)
    214 {
    215     uint32_t cLoops = 0;
    216     uint8_t bStatus;
    217     do
    218     {
    219         if ((++cLoops & 0xfffff) == 0)
    220             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
    221         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
    222     } while (    (bStatus & (ATA_STS_BUSY | ATA_STS_DRDY)) != ATA_STS_DRDY
    223              && !(bStatus & ATA_STS_ERR) );
    224     return bStatus;
    225 }
    226 
    227 uint8_t AtaWaitBusyForData(void)
    228 {
    229     uint32_t cLoops = 0;
    230     uint8_t bStatus;
    231     do
    232     {
    233         if ((++cLoops & 0xfffff) == 0)
    234             fprintf(stderr, "AtaWaitBusyForData: cLoops=%#lx\n", cLoops);
    235         bStatus = inp(ATA_REG_STATUS(g_uBasePort));
    236     } while (    (bStatus & (ATA_STS_BUSY | ATA_STS_DRQ)) != ATA_STS_DRQ
    237              && !(bStatus & ATA_STS_ERR) );
    238     return bStatus;
    239 }
    240 
    241 uint8_t AtaSubmitCommandAndWait(uint8_t bCommand)
    242 {
    243 
    244     outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
    245     ATA_DELAY_400NS();
    246     return AtaWaitBusy();
    247 }
    248 
    249 uint8_t AtaSubmitCommandAndWaitForData(uint8_t bCommand)
    250 {
    251 
    252     outp(ATA_REG_COMMAND(g_uBasePort), bCommand);
    253     ATA_DELAY_400NS();
    254     return AtaWaitBusyForData();
    255 }
    256 
    257 uint8_t AtaSelectDevice(uint8_t bDevice)
    258 {
    259     outp(ATA_REG_DEVICE_SELECT(g_uBasePort), g_bDevice);
    260     ATA_DELAY_400NS();
    261     return AtaWaitBusyDeviceReady();
    262 }
    263 
    264 void AtaSetSectorAddress(uint32_t iSector, uint8_t bDevice)
    265 {
    266     if (g_fUseLbaMode)
    267     {
    268         outp(ATA_REG_LBA_0_7(g_uBasePort), iSector & 0xff);
    269         outp(ATA_REG_LBA_8_15(g_uBasePort), (iSector >> 8) & 0xff);
    270         outp(ATA_REG_LBA_16_23(g_uBasePort), (iSector >> 16) & 0xff);
    271         outp(ATA_REG_LBA_24_27_MODE(g_uBasePort), ((iSector >> 24) & 0x0f) | ATA_LBA_MODE | bDevice);
    272     }
    273     else
    274     {
    275         uint16_t iCyl = iSector / g_cSectorsPerCylinder;
    276         uint16_t iRem = iSector % g_cSectorsPerCylinder;
    277         uint8_t  iHd  = iRem / g_cSectorsPerTrack;
    278         uint8_t  iSec = iRem % g_cSectorsPerTrack;
    279 
    280         outp(ATA_REG_SECTOR_NUMBER(g_uBasePort), iSec);
    281         outp(ATA_REG_CYLINDER_LOW(g_uBasePort), iCyl & 0xff);
    282         outp(ATA_REG_CYLINDER_HIGH(g_uBasePort), iCyl >> 8);
    283         outp(ATA_REG_HEAD(g_uBasePort), iHd | bDevice);
    284     }
    285 }
    286 
    287 void AtaReadData(void *pvBuf, size_t cb, uint8_t f8BitData)
    288 {
    289     uint16_t  uDataPort = ATA_REG_DATA(g_uBasePort);
    290     uint16_t *pu16      = (uint16_t *)pvBuf;
    291     cb >>= 1;
    292 
    293     if (f8BitData)
    294     {
    295         while (cb-- > 0)
    296         {
    297             uint8_t b1 = inp(uDataPort);
    298             uint8_t b2 = inp(uDataPort);
    299             *pu16++ = b1 | ((uint16_t)b2 << 8);
    300         }
    301     }
    302     else
    303     {
    304         while (cb-- > 0)
    305             *pu16++ = inpw(uDataPort);
    306     }
    307 }
    308 
    309 ////static uint8_t AtaWaitForDataRequest(size_t cbLeft)
    310 ////{
    311 ////    uint16_t uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    312 ////    uint8_t  bStsFirst = inp(uAltStsPort);
    313 ////    uint8_t  bSts = bStsFirst;
    314 ////    uint32_t cLoops = 0;
    315 ////    do
    316 ////    {
    317 ////        if (++cLoops & 0xffff)
    318 ////        {
    319 ////static unsigned x = 0;
    320 ////if (x < 16)
    321 ////{
    322 ////    printf("AtaWaitForDataRequest: bFirst=%#x bLast=%#x cbLeft=%#x\n", bStsFirst, bSts, cbLeft);
    323 ////    x++;
    324 ////}
    325 ////            break;
    326 ////        }
    327 ////        bSts = inp(uAltStsPort);
    328 ////    } while (!(bSts & (ATA_STS_DRQ | ATA_STS_ERR)));
    329 ////    return bSts;
    330 ////}
    331 
    332 void xchg(uint8_t volatile *pb);
    333 #pragma aux xchg = \
    334     "xchg [si], cx" \
    335     "xchg [si], cx" \
    336     "xchg [si], cx" \
    337     "xchg [si], cx" \
    338     parm [si] \
    339     modify exact [cx];
    340 
    341 void AtaWriteData(void const *pvBuf, size_t cb, uint8_t f8BitData)
    342 {
    343 //    uint16_t        uAltStsPort = ATA_REG_ALT_STATUS(g_uBasePort);
    344     uint16_t register uDataPort = ATA_REG_DATA(g_uBasePort);
    345 
    346     if (f8BitData)
    347     {
    348 #if 0
    349         uint8_t const   * volatile pbSrc = (uint8_t const *)pvBuf;
    350         uint8_t volatile ab[64];
    351         uint8_t volatile *pb = &ab[0];
    352         while (((uintptr_t)pb & 0x1f) != 0x1f)
    353             pb++;
    354         //uint8_t  bSts1, bSts2;
    355 inp(0x21);
    356 xchg(pb);
    357 
    358         while (cb-- > 0)
    359         {
    360             uint8_t b = *pbSrc++;
    361             xchg(pb);
    362             outp(uDataPort, b);
    363             xchg(pb);
    364             b = *pbSrc++;
    365             xchg(pb);
    366 //inp(0x21);
    367             outp(uDataPort, b);
    368             xchg(pb);
    369 //inp(0x21);
    370             //if (cb < 30)
    371             //{
    372             //    if ((cb & 3) == 3)
    373             //        printf("bSts1=%#x bSts2=%#x ", bSts1, bSts2);
    374             //    else
    375             //        printf("bSts1=%#x bSts2=%#x\n", bSts1, bSts2);
    376             //}
    377         }
    378 inp(0x21);
    379 #else
    380         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    381         cb >>= 1;
    382         while (cb-- > 0)
    383         {
    384             uint16_t register u16 = *pu16++;
    385             outp(uDataPort, (uint8_t)u16);
    386             outp(uDataPort, (uint8_t)(u16 >> 8));
    387         }
    388 #endif
    389     }
    390     else
    391     {
    392         uint16_t const *pu16      = (uint16_t const *)pvBuf;
    393         cb >>= 1;
    394         while (cb-- > 0)
    395             outp(uDataPort, *pu16++);
    396     }
    397 }
    398 
    399 int AtaReadSector(uint32_t iSector, void *pvBuf)
    400 {
    401     uint8_t bSts = AtaWaitBusy();
    402     if (bSts & ATA_STS_ERR)
    403         return AtaError(bSts, "Prepping for reading sector %lu", iSector);
    404 
    405 printf("AtaReadSector #2\n");
    406     bSts = AtaSelectDevice(g_bDevice);
    407     if (bSts & ATA_STS_ERR)
    408         return AtaError(bSts, "Selecting device for reading sector %lu", iSector);
    409 
    410 //printf("AtaReadSector #3\n");
    411     outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
    412     outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
    413     AtaSetSectorAddress(iSector, g_bDevice);
    414 
    415 //printf("AtaReadSector #4\n");
    416     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_READ_SECTORS);
    417     if (bSts & ATA_STS_ERR)
    418         return AtaError(bSts, "Reading sector %lu", iSector);
    419 
    420     if (!(bSts & ATA_STS_DRQ))
    421         return AtaError(bSts, "DRQ not set after reading sector %lu", iSector);
    422 
    423 
    424 //printf("AtaReadSector #5\n");
    425     AtaReadData(pvBuf, 512, g_f8BitData);
    426 //printf("AtaReadSector #6: bSts=%#x\n", inp(ATA_REG_ALT_STATUS(g_uBasePort)));
    427     bSts = inp(ATA_REG_STATUS(g_uBasePort));
    428     if ((bSts & ATA_STS_DRQ))
    429         return AtaError(bSts, "DRQ is still set after reading sector %lu", iSector);
    430     if ((bSts & ATA_STS_ERR))
    431         return AtaError(bSts, "ERR is set after reading sector %lu (#2)", iSector);
    432     return 0;
    433 }
    434 
    435 int AtaWriteSector(uint32_t iSector, void const *pvBuf)
    436 {
    437 //int x = printf("AtaWriteSector #1\n");
    438     uint8_t bSts = AtaWaitBusy();
    439     if (bSts & ATA_STS_ERR)
    440         return AtaError(bSts, "Prepping for writing sector %lu", iSector);
    441 printf("AtaWriteSector #2\n");
    442 
    443     bSts = AtaSelectDevice(g_bDevice);
    444     if (bSts & ATA_STS_ERR)
    445         return AtaError(bSts, "Selecting device for writing sector %lu", iSector);
    446 
    447     outp(ATA_REG_FEATURES(g_uBasePort), 0x0);
    448     outp(ATA_REG_SECTOR_COUNT(g_uBasePort), 1);
    449     AtaSetSectorAddress(iSector, g_bDevice);
    450 
    451 //printf("AtaWriteSector #3\n");
    452     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_WRITE_SECTORS);
    453     if (bSts & ATA_STS_ERR)
    454         return AtaError(bSts, "writing sector (#1) %lu", iSector);
    455     if (!(bSts & ATA_STS_DRQ))
    456         return AtaError(bSts, "DRQ not set after writing sector (#1) %lu", iSector);
    457 
    458 //printf("AtaWriteSector #4\n");
    459     AtaWriteData(pvBuf, 512, g_f8BitData);
    460 //printf("AtaWriteSector #5\n");
    461     ATA_DELAY_400NS();
    462     bSts = AtaWaitBusy();
    463 //printf("AtaWriteSector #6\n");
    464     if (bSts & ATA_STS_ERR)
    465         return AtaError(bSts, "writing sector (#2) %lu", iSector);
    466     if (bSts & ATA_STS_DRQ)
    467         return AtaError(bSts, "DRQ is set after writing sector (#2) %lu", iSector);
    468 
    469     return 0;
    470 }
    471 
    472 int AtaIdentifyDevice(uint8_t bDevice, void *pvBuf)
    473 {
    474     uint8_t bSts = AtaWaitBusy();
    475     if (bSts & ATA_STS_ERR)
    476         return AtaError(bSts, "Prepping for device %#x identification", bDevice);
    477 
    478     bSts = AtaSelectDevice(g_bDevice);
    479     if (bSts & ATA_STS_ERR)
    480         return AtaError(bSts, "Selecting device %#x for identification", bDevice);
    481 
    482     outp(ATA_REG_FEATURES(g_uBasePort),         0);
    483     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     0);
    484     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
    485     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
    486     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
    487     //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
    488 
    489     bSts = AtaSubmitCommandAndWaitForData(ATA_CMD_IDENTIFY_DEVICE);
    490     if (bSts & ATA_STS_ERR)
    491         return AtaError(bSts, "Device %#x identification", bDevice);
    492     if (!(bSts & ATA_STS_DRQ))
    493         return AtaError(bSts, "DRQ not set after device %#x identification", bDevice);
    494 
    495     AtaReadData(pvBuf, 512, g_f8BitData);
    496     return 0;
    497 }
    498 
    499 int AtaSetFeature(uint8_t bDevice, uint8_t bFeature, uint8_t bValue)
    500 {
    501     uint8_t bSts = AtaWaitBusy();
    502     if (bSts & ATA_STS_ERR)
    503         return AtaError(bSts, "Prepping for setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
    504 
    505     bSts = AtaSelectDevice(g_bDevice);
    506     if (bSts & ATA_STS_ERR)
    507         return AtaError(bSts, "Selecting device %#x for setting feature %#x (%#x)", bDevice, bFeature, bValue);
    508 
    509     outp(ATA_REG_FEATURES(g_uBasePort),         bFeature);
    510     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     0);
    511     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    bValue);
    512     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
    513     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
    514     //outp(ATA_REG_HEAD(g_uBasePort), g_bDevice);
    515 
    516     bSts = AtaSubmitCommandAndWait(ATA_CMD_SET_FEATURES);
    517     if (bSts & ATA_STS_ERR)
    518         return AtaError(bSts, "Setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
    519     if (bSts & ATA_STS_DRQ)
    520         return AtaError(bSts, "DRQ is set after setting device %#x feature %#x (%#x)", bDevice, bFeature, bValue);
    521     return 0;
    522 }
    523 
    524 int AtaInitDeviceParams(uint8_t bDevice, uint8_t cSectorsPerTrack, uint8_t cHeads)
    525 {
    526     uint8_t bSts = AtaWaitBusy();
    527     if (bSts & ATA_STS_ERR)
    528         return AtaError(bSts, "Prepping for device %#x parameter initialization", bDevice);
    529 
    530     bSts = AtaSelectDevice(g_bDevice);
    531     if (bSts & ATA_STS_ERR)
    532         return AtaError(bSts, "Selecting device for device %#x parameter initialization", bDevice);
    533 
    534     outp(ATA_REG_FEATURES(g_uBasePort),         0);
    535     outp(ATA_REG_SECTOR_COUNT(g_uBasePort),     cSectorsPerTrack);
    536     outp(ATA_REG_SECTOR_NUMBER(g_uBasePort),    0);
    537     outp(ATA_REG_CYLINDER_LOW(g_uBasePort),     0);
    538     outp(ATA_REG_CYLINDER_HIGH(g_uBasePort),    0);
    539     outp(ATA_REG_HEAD(g_uBasePort), g_bDevice | cHeads);
    540 
    541     bSts = AtaSubmitCommandAndWait(ATA_CMD_INIT_DEVICE_PARAMS);
    542     if (bSts & ATA_STS_ERR)
    543         return AtaError(bSts, "Device %#x parameter initialization", bDevice);
    544     if (bSts & ATA_STS_DRQ)
    545         return AtaError(bSts, "DRQ is set after device %#x parameter initialization", bDevice);
    546     return 0;
    547 }
    548 
    549 int AtaReset(void)
    550 {
    551     uint8_t bSts;
    552 
    553     /* Set the reset flat. */
    554     outp(ATA_REG_CONTROL(g_uBasePort), ATA_CTL_SRST);
    555 
    556     /* Wait for the busy flag response. */
    557     ATA_DELAY_400NS();
    558     ATA_DELAY_400NS();
    559     while (!(bSts = inp(ATA_REG_STATUS(g_uBasePort))) & ATA_STS_BUSY)
    560         ATA_DELAY_400NS();
    561 
    562     /* Clear the reset flag. */
    563     outp(ATA_REG_CONTROL(g_uBasePort), 0);
    564     ATA_DELAY_400NS();
    565 
    566     /* Wait for the controller to become non-busy. */
    567     bSts = AtaWaitBusy();
    568     if (bSts & ATA_STS_ERR)
    569         return AtaError(bSts, "Software reset failed");
    570     return 0;
    571 }
    572 
    573 
    574 int AtaInit(void)
    575 {
    576     uint8_t bSts = inp(ATA_REG_ALT_STATUS(g_uBasePort));
    577     printf("alt status=");
    578     AtaPrintStatus(stdout, bSts);
    579     printf("\n");
    580 
    581     bSts = inp(ATA_REG_STATUS(g_uBasePort));
    582     printf("    status=");
    583     AtaPrintStatus(stdout, bSts);
    584     printf("\n");
    585 
    586     if (AtaReset() != 0)
    587         return -1;
    588 
    589     /* Enable 8-bit data transfers (just to be on the safe side). */
    590     AtaSetFeature(g_bDevice, ATA_FEATURE_EN_8BIT_DATA, 0);
    591 
    592     /* Identify the device. */
    593     memset(g_awIdentify, 0, sizeof(g_awIdentify));
    594     if (AtaIdentifyDevice(g_bDevice, g_awIdentify) != 0)
    595         return -1;
    596 
    597     /** @todo this is rather simple... */
    598     g_cCylinders = g_awIdentify[1];
    599     g_cHeads     = g_awIdentify[3];
    600     g_cSectorsPerTrack = g_awIdentify[6];
    601     g_cSectorsPerCylinder = g_cHeads * g_cSectorsPerTrack;
    602     printf("Device %#x parameters: %u cylinders, %u heads, %u sectors\n",
    603            g_bDevice, g_cCylinders, g_cHeads, g_cSectorsPerTrack);
    604 
    605     /* Disable stuff and try select pio modes. */
    606     AtaSetFeature(g_bDevice, ATA_FEATURE_DI_WRITE_CACHE, 0);
    607     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_DEFAULT_NO_IORDY);
    608     AtaSetFeature(g_bDevice, ATA_FEATURE_SET_XFERMODE, ATA_FV_XFERMODE_PIO_MODE_XXX_FLAG | 0);
    609 
    610     return 0;
    611 }
    612 
    613 
    61461
    61562
     
    746193
    747194
    748 int GetDriveParams(void)
     195int GetDriveParams(uint8_t bDevice)
    749196{
    750197#ifdef USE_INT13H
    751198    return Int13hInit();
    752199#else
    753     return AtaInit();
     200    return 0;
    754201#endif
    755202}
     
    791238     */
    792239    uint32_t iSector = 3;
     240    uint8_t  bDevice = ATA_DEV_MASTER;
    793241    g_bDrv = 0x80;
    794     g_bDevice = ATA_DEV_MASTER;
    795242
    796243    if (argc > 3)
     
    812259    if (argc > 2)
    813260    {
    814         unsigned long uTmp = strtoul(argv[2], NULL, 0);
    815         if (uTmp < 0x80 || uTmp > 0x8f)
    816         {
    817             fprintf(stderr, "error: drive number is out of bounds: %s (%lu)\n", argv[1], uTmp);
     261        if (AtaInitFromArgv(2, argc, argv) != 0)
    818262            return usage();
    819         }
    820         g_bDrv = (uint8_t)uTmp;
    821         g_bDevice = g_bDrv == 0x80 ? ATA_DEV_MASTER : ATA_DEV_SLAVE; /* simplified */
    822263    }
    823264
     
    825266     * Detect drive parameters.
    826267     */
    827     if (GetDriveParams() == 0)
     268    if (GetDriveParams(bDevice) == 0)
    828269    {
    829270        static uint8_t s_abSaved[512];
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette