Ignore:
Timestamp:
Jul 13, 2017, 12:27:52 PM (7 years ago)
Author:
max@…
Message:

implement a basic ATA driver

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/hal/x86_64/drivers/soclib_bdv.c

    r76 r194  
    2828#include <spinlock.h>
    2929
     30#include <hal_internal.h>
     31
     32#define PIO_ATA_CBR_BASE        0x1F0
     33#       define ATA_DATA         0x000
     34#       define ATA_ERRFEAT      0x001 /* two regs */
     35#       define ATA_SCR          0x002
     36#       define ATA_SNR          0x003 /* lba0 */
     37#       define ATA_CLR          0x004 /* lba1 */
     38#       define ATA_CHR          0x005 /* lba2 */
     39#       define ATA_DHR          0x006 /* drive | lba3 */
     40#       define ATA_SR           0x007
     41#               define ATA_SR_ERR       0x01
     42#               define ATA_SR_IDX       0x02
     43#               define ATA_SR_CORR      0x04
     44#               define ATA_SR_DRQ       0x08
     45#               define ATA_SR_DSC       0x10
     46#               define ATA_SR_DF        0x20
     47#               define ATA_SR_DRDY      0x40
     48#               define ATA_SR_BSY       0x80
     49#       define ATA_CR           0x007 /* two regs */
     50
     51#define ATA_CMD_READ_SECTORS_RETRY      0x20
     52#define ATA_CMD_READ_SECTORS_NORETRY    0x21
     53#define ATA_CMD_WRITE_SECTORS_RETRY     0x30
     54#define ATA_CMD_WRITE_SECTORS_NORETRY   0x31
     55#define ATA_CMD_IDENTIFY                0xEC
     56
     57static inline uint16_t ata_data_read()
     58{
     59        return in16(PIO_ATA_CBR_BASE + ATA_DATA);
     60}
     61
     62static inline void ata_data_write(uint16_t val)
     63{
     64        out16(PIO_ATA_CBR_BASE + ATA_DATA, val);
     65}
     66
     67static inline uint8_t ata_cbr_read(uint32_t reg)
     68{
     69        return in8(PIO_ATA_CBR_BASE + reg);
     70}
     71
     72static inline void ata_cbr_write(uint32_t reg, uint8_t val)
     73{
     74        out8(PIO_ATA_CBR_BASE + reg, val);
     75}
     76
     77static inline int ata_wait()
     78{
     79        uint8_t status;
     80
     81        while (!(ata_cbr_read(ATA_SR) & ATA_SR_DRQ));
     82        status = ata_cbr_read(ATA_SR);
     83        return ((status & ATA_SR_ERR) ? -1 : 0);
     84}
     85
     86static void ata_prepare(uint8_t slave, uint32_t lba, uint8_t count)
     87{
     88        ata_cbr_write(ATA_ERRFEAT, 0x00); /* NULL byte to port 0x1F1 */
     89        ata_cbr_write(ATA_SCR, count); /* sector count */
     90
     91        /* set the lba */
     92        ata_cbr_write(ATA_SNR, (lba >> 0) & 0xFF);
     93        ata_cbr_write(ATA_CLR, (lba >> 8) & 0xFF);
     94        ata_cbr_write(ATA_CHR, (lba >> 16)& 0xFF);
     95
     96        /* set the drive and lba3 */
     97        ata_cbr_write(ATA_DHR, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F));
     98}
     99
     100static int ata_read(uint8_t count, char *buf)
     101{
     102        uint16_t tmpword;
     103        int idx;
     104
     105        /* wait for the drive to signal that it's ready */
     106        if (ata_wait() == -1)
     107                return -1;
     108
     109        for (idx = 0; idx < 256 * count; idx++) {
     110                tmpword = ata_data_read();
     111                buf[idx * 2] = (uint8_t)(tmpword & 0xFF);
     112                buf[idx * 2 + 1] = (uint8_t)(tmpword >> 8);
     113        }
     114
     115        return 0;
     116}
     117
     118static int ata_write(uint8_t count, char *buf)
     119{
     120        uint16_t tmpword;
     121        int idx;
     122
     123        /* wait for the drive to signal that it's ready */
     124        if (ata_wait() == -1)
     125                return -1;
     126
     127        for (idx = 0; idx < 256 * count; idx++) {
     128                tmpword = (buf[idx * 2 + 1] << 8) | buf[idx * 2];
     129                ata_data_write(tmpword);
     130        }
     131
     132        return 0;
     133}
     134
     135static uint16_t bswap16(uint16_t x)
     136{
     137        return ((x << 8) & 0xFF00) | ((x >> 8) & 0x00FF);
     138}
     139
     140static void ata_init()
     141{
     142        uint8_t id[512];
     143        uint16_t tmpw, *p;
     144        size_t idx;
     145        char *model;
     146        uint8_t ncyl;
     147        int ret;
     148
     149        ata_prepare(0, 0, 0);
     150        ata_cbr_write(ATA_CR, ATA_CMD_IDENTIFY);
     151
     152        /* wait for the drive to signal that it's ready */
     153        ret = ata_wait();
     154        if (ret == -1)
     155                x86_printf("-> unable to identify ATA\n");
     156
     157        for (idx = 0; idx < 256; idx++) {
     158                tmpw = ata_data_read();
     159                id[idx * 2]     = (uint8_t)((tmpw >> 0) & 0xFF);
     160                id[idx * 2 + 1] = (uint8_t)((tmpw >> 8) & 0xFF);
     161        }
     162
     163        ncyl = id[0] & 0x1;
     164        x86_printf("-> cyl: %z\n", (uint64_t)ncyl);
     165
     166        for (idx = 27*2; idx < 46*2; idx += 2) {
     167                p = (uint16_t *)(&id[idx]);
     168                *p = bswap16(*p);
     169        }
     170
     171        model = &id[27*2];
     172        id[46*2] = '\0';
     173        x86_printf("-> ATA model: '%s'\n", model);
     174}
     175
     176/* -------------------------------------------------------------------------- */
     177
     178
    30179void soclib_bdv_init( chdev_t * chdev )
    31180{
    32 
     181        ata_init();
    33182}
    34183
     
    36185{
    37186
     187        x86_panic("myshit!\n");
     188
     189        uint32_t   cmd_type;     // IOC_READ / IOC_WRITE / IOC_SYNC_READ
     190        uint32_t   lba;          // command argument
     191        uint32_t   count;        // command argument
     192        xptr_t     buf_xp;       // command argument
     193
     194        // get client thread cluster and local pointer
     195        cxy_t      th_cxy = GET_CXY( th_xp );
     196        thread_t * th_ptr = (thread_t *)GET_PTR( th_xp );
     197
     198        // get command arguments and extended pointer on IOC device
     199        cmd_type =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->command.ioc.type   ) );
     200        lba      =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->command.ioc.lba    ) );
     201        count    =         hal_remote_lw ( XPTR( th_cxy , &th_ptr->command.ioc.count  ) );
     202        buf_xp   = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->command.ioc.buf_xp ) );
     203
     204        /* execute operation */
     205        ata_prepare(0, lba, count);
     206        if (cmd_type == IOC_WRITE) {
     207                ata_cbr_write(ATA_CR, ATA_CMD_WRITE_SECTORS_RETRY);
     208        } else {
     209                ata_cbr_write(ATA_CR, ATA_CMD_READ_SECTORS_RETRY);
     210        }
     211
     212        /* waiting policy depends on the command type */
     213        if (cmd_type == IOC_SYNC_READ) {
     214                ata_read(count, (char *)buf_xp);
     215        } else {
     216                x86_panic("!IOC_SYNC_READ not supported");
     217        }
    38218}
    39219
Note: See TracChangeset for help on using the changeset viewer.