source: trunk/hal/x86_64/drivers/soclib_bdv.c @ 194

Last change on this file since 194 was 194, checked in by max@…, 7 years ago

implement a basic ATA driver

File size: 5.5 KB
Line 
1/*
2 * soclib_bdv.c - soclib simple block device driver implementation.
3 *
4 * Author     Alain Greiner (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <chdev.h>
25#include <dev_ioc.h>
26#include <soclib_bdv.h>
27#include <thread.h>
28#include <spinlock.h>
29
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
179void soclib_bdv_init( chdev_t * chdev )
180{
181        ata_init();
182}
183
184void __attribute__ ((noinline)) soclib_bdv_cmd( xptr_t th_xp )
185{
186
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        }
218}
219
220void __attribute__ ((noinline)) soclib_bdv_isr( chdev_t * chdev )
221{
222
223}
224
Note: See TracBrowser for help on using the repository browser.