kern

view src/ata.c @ 86:379332fc1667

implementing ata read/write
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 07 Dec 2011 14:03:11 +0200
parents 4ef83db5f4cd
children 178d5a95e6de
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <inttypes.h>
6 #include <assert.h>
7 #include "ata.h"
8 #include "intr.h"
9 #include "asmops.h"
10 #include "mutex.h"
12 /* registers */
13 #define REG_DATA 0 /* R/W */
14 #define REG_ERROR 1 /* R */
15 #define REG_FEATURES 1 /* W */
16 #define REG_COUNT 2 /* R/W */
17 #define REG_LBA0 3 /* R/W */
18 #define REG_LBA1 4 /* R/W */
19 #define REG_LBA2 5 /* R/W */
20 #define REG_DEVICE 6 /* R/W */
21 #define REG_CMD 7 /* W */
22 #define REG_STATUS 7 /* R */
24 #define REG_CTL 518
25 #define REG_ALTSTAT 518
27 /* status bit fields */
28 #define ST_ERR (1 << 0)
29 #define ST_DRQ (1 << 3)
30 #define ST_DRDY (1 << 6)
31 #define ST_BSY (1 << 7)
33 /* device select bit in control register */
34 #define DEV_SEL(x) (((x) & 1) << 4)
35 #define DEV_LBA (1 << 6)
37 /* ATA commands */
38 #define CMD_IDENTIFY 0xec
39 #define CMD_READ 0x20
40 #define CMD_READ48 0x24
41 #define CMD_WRITE 0x30
42 #define CMD_WRITE48 0x34
45 struct device {
46 int id; /* id of the device on its ATA interface (0 master, 1 slave) */
47 int iface; /* ATA interface for this device (0 or 1) */
48 int port_base; /* interface I/O port base */
50 uint32_t nsect_lba;
51 uint64_t nsect_lba48;
52 };
55 static int identify(struct device *dev, int iface, int id);
56 static void select_dev(struct device *dev);
57 static int wait_busy(struct device *dev);
58 static int wait_drq(struct device *dev);
59 static void read_data(struct device *dev, void *buf);
60 static inline uint8_t read_reg8(struct device *dev, int reg);
61 static inline uint16_t read_reg16(struct device *dev, int reg);
62 static inline void write_reg8(struct device *dev, int reg, uint8_t val);
63 static inline void write_reg16(struct device *dev, int reg, uint16_t val);
64 static void ata_intr(int inum);
65 static void *atastr(void *res, void *src, int n);
66 static char *size_str(uint64_t nsect, char *buf);
68 /* last drive selected on each bus */
69 static int drvsel[2] = {-1, -1};
71 /* 4 possible devices: 2 ATA interfaces with 2 devices each.
72 * this will never change unless we start querying the PCI config space
73 * for additional drives (in which case this whole init code must be
74 * rewritten anyway), but I like it spelt out like this.
75 */
76 #define MAX_IFACES 2
77 #define MAX_DEV (MAX_IFACES * 2)
78 static struct device devices[MAX_DEV];
80 static int use_irq;
82 /* This serves as a sync point for I/O. While the mutex is held,
83 * some process is doing I/O and all the others must wait.
84 */
85 static mutex_t pending;
88 void init_ata(void)
89 {
90 int i;
92 interrupt(IRQ_TO_INTR(15), ata_intr);
94 for(i=0; i<MAX_DEV; i++) {
95 int iface = i / MAX_IFACES;
96 int id = i % MAX_IFACES;
98 if(identify(devices + i, iface, id) == -1) {
99 devices[i].id = -1;
100 }
101 }
103 /* init code done, from now on use the irq sleep/wakeup mechanism */
104 use_irq = 1;
105 }
107 int ata_read_pio(int devno, uint64_t sect, void *buf)
108 {
109 int cmd, st, res = -1;
110 uint32_t sect_low;
111 struct device *dev = device + devno;
113 if(dev->id == -1) {
114 return -1;
115 }
117 if(use_irq) {
118 /* wait for the interface to become available */
119 mutex_lock(&pending);
120 }
122 select_dev(dev);
124 /* LBA48 requires the high-order bits first */
125 if(sect >= dev->nsect_lba) {
126 uint32_t sect_high = (uint32_t)(sect >> 24);
127 sect_low = (uint32_t)sect & 0xffffff;
129 if(sect >= dev->nsect_lba48) {
130 goto end;
131 }
132 cmd = CMD_READ48;
134 write_reg8(dev, REG_COUNT, 0);
135 write_reg8(dev, REG_LBA0, sect_high & 0xff);
136 write_reg8(dev, REG_LBA1, (sect_high >> 8) & 0xff);
137 write_reg8(dev, REG_LBA2, (sect_high >> 16) & 0xff);
138 } else {
139 cmd = CMD_READ;
140 sect_low = (uint32_t)sect & 0xffffff;
141 }
143 write_reg8(dev, REG_COUNT, 1);
144 write_reg8(dev, REG_LBA0, sect_low & 0xff);
145 write_reg8(dev, REG_LBA1, (sect_low >> 8) & 0xff);
146 write_reg8(dev, REG_LBA2, (sect_low >> 16) & 0xff);
147 write_reg8(dev, REG_DEVICE, ((sect_low >> 24) & 0xf) | DEV_LBA | DEV_SEL(dev->id))
148 /* execute */
149 write_reg8(dev, REG_CMD, cmd);
151 /* wait for the data to become available */
152 do {
153 if(use_irq) {
154 /* also sleep on the mutex if we're called from userspace */
155 wait(&pending);
156 }
157 } while((st = read_reg8(dev, REG_ALTSTAT)) & (ST_DRQ | ST_ERR) == 0);
159 if(st & ST_ERR) {
160 print_error();
161 goto end;
162 }
164 /* read the data and we're done */
165 read_data(dev, buf);
166 res = 0;
167 end:
168 if(use_irq) {
169 mutex_unlock(&pending);
170 }
171 return res;
172 }
174 int ata_write_pio(int devno, uint64_t sect, void *buf)
175 {
176 if(dev[devno].id == -1) {
177 return -1;
178 }
179 }
181 static int identify(struct device *dev, int iface, int id)
182 {
183 /* base address of the two ATA interfaces */
184 static const int port_base[] = {0x1f0, 0x170};
185 unsigned char st;
186 uint16_t *info;
187 char textbuf[42]; /* at most we need 40 chars for ident strings */
189 dev->id = id;
190 dev->iface = iface;
191 dev->port_base = port_base[iface];
193 /* a status of 0xff means there's no drive on the interface */
194 if((st = read_reg8(dev, REG_ALTSTAT)) == 0xff) {
195 return -1;
196 }
198 select_dev(dev);
200 write_reg8(dev, REG_CMD, CMD_IDENTIFY);
202 if(!(st = read_reg8(dev, REG_ALTSTAT)) || (st & ST_ERR)) {
203 /* does not exist */
204 return -1;
205 }
206 if(wait_busy(dev) == -1) {
207 /* got ST_ERR, not ATA */
208 return -1;
209 }
211 info = malloc(512);
212 assert(info);
214 /* read the device information */
215 read_data(dev, info);
217 /* print model and serial */
218 printf("ata%d: %s", (dev->iface << 1) | dev->id, atastr(textbuf, info + 27, 40));
219 printf(" [s/n: %s]", atastr(textbuf, info + 10, 20));
221 dev->nsect_lba = *(uint32_t*)(info + 60);
222 dev->nsect_lba48 = *(uint64_t*)(info + 100) & 0xffffffffffffull;
224 if(!dev->nsect_lba) {
225 printf(" drive does not support LBA, ignoring!\n");
226 free(info);
227 return -1;
228 }
230 if(dev->nsect_lba48) {
231 size_str(dev->nsect_lba48, textbuf);
232 } else {
233 size_str(dev->nsect_lba, textbuf);
234 }
235 printf(" size: %s\n", textbuf);
237 free(info);
238 return 0;
239 }
241 static void select_dev(struct device *dev)
242 {
243 /* if this is the currently selected device, thy work is done */
244 if(drvsel[dev->iface] == dev->id)
245 return;
247 /* wait for BSY and DRQ to clear */
248 while(read_reg8(dev, REG_ALTSTAT) & (ST_BSY | ST_DRQ));
250 /* set the correct device bit to the device register */
251 write_reg8(dev, REG_DEVICE, DEV_SEL(dev->id));
253 /* wait a bit to allow the device time to respond */
254 iodelay(); iodelay(); iodelay(); iodelay();
255 }
257 static int wait_busy(struct device *dev)
258 {
259 unsigned char st;
261 do {
262 st = read_reg8(dev, REG_ALTSTAT);
263 } while((st & ST_BSY) && !(st & ST_ERR));
265 return st & ST_ERR ? -1 : 0;
266 }
268 static int wait_drq(struct device *dev)
269 {
270 unsigned char st;
272 do {
273 st = read_reg8(dev, REG_ALTSTAT);
274 } while(!(st & (ST_DRQ | ST_ERR)));
276 return st & ST_ERR ? -1 : 0;
277 }
279 static void read_data(struct device *dev, void *buf)
280 {
281 int i;
282 uint16_t *ptr = buf;
284 /* wait for the data request from the drive */
285 wait_drq(dev);
287 /* ready to transfer */
288 for(i=0; i<256; i++) {
289 *ptr++ = read_reg16(dev, REG_DATA);
290 }
291 }
293 static inline uint8_t read_reg8(struct device *dev, int reg)
294 {
295 uint8_t val;
296 inb(val, dev->port_base + reg);
297 return val;
298 }
300 static inline uint16_t read_reg16(struct device *dev, int reg)
301 {
302 uint16_t val;
303 inw(val, dev->port_base + reg);
304 return val;
305 }
307 static inline void write_reg8(struct device *dev, int reg, uint8_t val)
308 {
309 outb(val, dev->port_base + reg);
310 }
312 static inline void write_reg16(struct device *dev, int reg, uint16_t val)
313 {
314 outw(val, dev->port_base + reg);
315 }
317 static void ata_intr(int inum)
318 {
319 printf("ATA interrupt\n");
320 }
322 static void *atastr(void *res, void *src, int n)
323 {
324 int i;
325 uint16_t *sptr = (uint16_t*)src;
326 char *dptr = res;
328 for(i=0; i<n/2; i++) {
329 *dptr++ = (*sptr & 0xff00) >> 8;
330 *dptr++ = *sptr++ & 0xff;
331 }
333 while(isspace(*--dptr));
334 *++dptr = 0;
335 return res;
336 }
338 static char *size_str(uint64_t nsect, char *buf)
339 {
340 static const char *suffix[] = {"kb", "mb", "gb", "tb", "pb", 0};
341 int i;
342 unsigned int rem;
344 /* start with kilobytes */
345 nsect /= 2;
347 for(i=0; nsect >= 1024 && suffix[i + 1]; i++) {
348 rem = nsect % 1024;
349 nsect /= 1024;
350 }
351 sprintf(buf, "%u.%u%s", (unsigned int)nsect, 100 * rem / 1024, suffix[i]);
352 return buf;
353 }