kern

view src/ata.c @ 89:2f555c81ae67

starting the filesystem
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 08 Dec 2011 18:19:35 +0200
parents a398bf73fe93
children 7ff2b4971216
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 "sched.h"
11 #include "mutex.h"
13 /* registers */
14 #define REG_DATA 0 /* R/W */
15 #define REG_ERROR 1 /* R */
16 #define REG_FEATURES 1 /* W */
17 #define REG_COUNT 2 /* R/W */
18 #define REG_LBA0 3 /* R/W */
19 #define REG_LBA1 4 /* R/W */
20 #define REG_LBA2 5 /* R/W */
21 #define REG_DEVICE 6 /* R/W */
22 #define REG_CMD 7 /* W */
23 #define REG_STATUS 7 /* R */
25 #define REG_CTL 518
26 #define REG_ALTSTAT 518
28 /* status bit fields */
29 #define ST_ERR (1 << 0)
30 #define ST_DRQ (1 << 3)
31 #define ST_DRDY (1 << 6)
32 #define ST_BSY (1 << 7)
34 /* device select bit in control register */
35 #define DEV_SEL(x) (((x) & 1) << 4)
36 #define DEV_LBA (1 << 6)
38 /* ATA commands */
39 #define CMD_IDENTIFY 0xec
40 #define CMD_READ 0x20
41 #define CMD_READ48 0x24
42 #define CMD_WRITE 0x30
43 #define CMD_WRITE48 0x34
46 struct device {
47 int id; /* id of the device on its ATA interface (0 master, 1 slave) */
48 int iface; /* ATA interface for this device (0 or 1) */
49 int port_base; /* interface I/O port base */
51 uint32_t nsect_lba;
52 uint64_t nsect_lba48;
53 };
56 static int readwrite_pio(int devno, uint64_t sect, void *buf, void (*rwdata)(struct device*, void*));
57 static int identify(struct device *dev, int iface, int id);
58 static void select_dev(struct device *dev);
59 static int wait_busy(struct device *dev);
60 static int wait_drq(struct device *dev);
61 static void read_data(struct device *dev, void *buf);
62 static void write_data(struct device *dev, void *buf);
63 static inline uint8_t read_reg8(struct device *dev, int reg);
64 static inline uint16_t read_reg16(struct device *dev, int reg);
65 static inline void write_reg8(struct device *dev, int reg, uint8_t val);
66 static inline void write_reg16(struct device *dev, int reg, uint16_t val);
67 static void ata_intr(int inum);
68 static void *atastr(void *res, void *src, int n);
69 static char *size_str(uint64_t nsect, char *buf);
70 static void print_error(int devid, int wr, uint32_t high, uint32_t low, unsigned char err);
72 /* last drive selected on each bus */
73 static int drvsel[2] = {-1, -1};
75 /* 4 possible devices: 2 ATA interfaces with 2 devices each.
76 * this will never change unless we start querying the PCI config space
77 * for additional drives (in which case this whole init code must be
78 * rewritten anyway), but I like it spelt out like this.
79 */
80 #define MAX_IFACES 2
81 #define MAX_DEV (MAX_IFACES * 2)
82 static struct device devices[MAX_DEV];
83 static int ndev;
85 /* This serves as a sync point for I/O. While the mutex is held,
86 * some process is doing I/O and all the others must wait.
87 */
88 static mutex_t pending;
91 void init_ata(void)
92 {
93 int i;
95 interrupt(IRQ_TO_INTR(15), ata_intr);
97 ndev = 0;
98 for(i=0; i<MAX_DEV; i++) {
99 int iface = i / MAX_IFACES;
100 int id = i % MAX_IFACES;
102 if(identify(devices + ndev, iface, id) == 0) {
103 ndev++;
104 }
105 }
106 }
108 int ata_num_devices(void)
109 {
110 return ndev;
111 }
113 int ata_read_pio(int devno, uint64_t sect, void *buf)
114 {
115 return readwrite_pio(devno, sect, buf, read_data);
116 }
118 int ata_write_pio(int devno, uint64_t sect, void *buf)
119 {
120 return readwrite_pio(devno, sect, buf, write_data);
121 }
123 static int readwrite_pio(int devno, uint64_t sect, void *buf, void (*rwdata)(struct device*, void*))
124 {
125 int use_irq, cmd, st, res = -1;
126 uint32_t sect_low, sect_high;
127 struct device *dev = devices + devno;
129 if(dev->id == -1) {
130 return -1;
131 }
132 use_irq = get_current_proc() != 0;
134 if(use_irq) {
135 /* wait for the interface to become available */
136 mutex_lock(&pending);
137 }
139 select_dev(dev);
141 /* LBA48 requires the high-order bits first */
142 if(sect >= dev->nsect_lba) {
143 sect_high = (uint32_t)(sect >> 24);
144 sect_low = (uint32_t)sect & 0xffffff;
146 if(sect >= dev->nsect_lba48) {
147 goto end;
148 }
149 cmd = CMD_READ48;
151 write_reg8(dev, REG_COUNT, 0);
152 write_reg8(dev, REG_LBA0, sect_high & 0xff);
153 write_reg8(dev, REG_LBA1, (sect_high >> 8) & 0xff);
154 write_reg8(dev, REG_LBA2, (sect_high >> 16) & 0xff);
155 } else {
156 cmd = CMD_READ;
157 sect_high = 0;
158 sect_low = (uint32_t)sect & 0xfffffff;
159 }
161 write_reg8(dev, REG_COUNT, 1);
162 write_reg8(dev, REG_LBA0, sect_low & 0xff);
163 write_reg8(dev, REG_LBA1, (sect_low >> 8) & 0xff);
164 write_reg8(dev, REG_LBA2, (sect_low >> 16) & 0xff);
165 write_reg8(dev, REG_DEVICE, ((sect_low >> 24) & 0xf) | DEV_LBA | DEV_SEL(dev->id));
166 /* execute */
167 write_reg8(dev, REG_CMD, cmd);
169 /* wait for the data to become available */
170 do {
171 if(use_irq) {
172 /* also sleep on the mutex if we're called from userspace */
173 wait(&pending);
174 }
175 } while(((st = read_reg8(dev, REG_ALTSTAT)) & (ST_DRQ | ST_ERR)) == 0);
177 if(st & ST_ERR) {
178 //print_error(int devid, int wr, uint32_t high, uint32_t low, unsigned char err);
179 unsigned char err;
181 err = read_reg8(dev, REG_ERROR);
182 print_error(devno, 0, sect_high, sect_low, err);
183 goto end;
184 }
186 /* read/write the data and we're done */
187 rwdata(dev, buf);
188 res = 0;
189 end:
190 if(use_irq) {
191 mutex_unlock(&pending);
192 }
193 return res;
194 }
196 static int identify(struct device *dev, int iface, int id)
197 {
198 /* base address of the two ATA interfaces */
199 static const int port_base[] = {0x1f0, 0x170};
200 unsigned char st;
201 uint16_t *info;
202 char textbuf[42]; /* at most we need 40 chars for ident strings */
204 dev->id = id;
205 dev->iface = iface;
206 dev->port_base = port_base[iface];
208 /* a status of 0xff means there's no drive on the interface */
209 if((st = read_reg8(dev, REG_ALTSTAT)) == 0xff) {
210 return -1;
211 }
213 select_dev(dev);
215 write_reg8(dev, REG_CMD, CMD_IDENTIFY);
217 if(!(st = read_reg8(dev, REG_ALTSTAT)) || (st & ST_ERR)) {
218 /* does not exist */
219 return -1;
220 }
221 if(wait_busy(dev) == -1) {
222 /* got ST_ERR, not ATA */
223 return -1;
224 }
226 info = malloc(512);
227 assert(info);
229 /* read the device information */
230 read_data(dev, info);
232 /* print model and serial */
233 printf("ata%d: %s", (dev->iface << 1) | dev->id, atastr(textbuf, info + 27, 40));
234 printf(" [s/n: %s]", atastr(textbuf, info + 10, 20));
236 dev->nsect_lba = *(uint32_t*)(info + 60);
237 dev->nsect_lba48 = *(uint64_t*)(info + 100) & 0xffffffffffffull;
239 if(!dev->nsect_lba) {
240 printf(" drive does not support LBA, ignoring!\n");
241 free(info);
242 return -1;
243 }
245 if(dev->nsect_lba48) {
246 size_str(dev->nsect_lba48, textbuf);
247 } else {
248 size_str(dev->nsect_lba, textbuf);
249 }
250 printf(" size: %s\n", textbuf);
252 free(info);
253 return 0;
254 }
256 static void select_dev(struct device *dev)
257 {
258 /* if this is the currently selected device, thy work is done */
259 if(drvsel[dev->iface] == dev->id)
260 return;
262 /* wait for BSY and DRQ to clear */
263 while(read_reg8(dev, REG_ALTSTAT) & (ST_BSY | ST_DRQ));
265 /* set the correct device bit to the device register */
266 write_reg8(dev, REG_DEVICE, DEV_SEL(dev->id));
268 /* wait a bit to allow the device time to respond */
269 iodelay(); iodelay(); iodelay(); iodelay();
270 }
272 static int wait_busy(struct device *dev)
273 {
274 unsigned char st;
276 do {
277 st = read_reg8(dev, REG_ALTSTAT);
278 } while((st & ST_BSY) && !(st & ST_ERR));
280 return st & ST_ERR ? -1 : 0;
281 }
283 static int wait_drq(struct device *dev)
284 {
285 unsigned char st;
287 do {
288 st = read_reg8(dev, REG_ALTSTAT);
289 } while(!(st & (ST_DRQ | ST_ERR)));
291 return st & ST_ERR ? -1 : 0;
292 }
294 static void read_data(struct device *dev, void *buf)
295 {
296 int i;
297 uint16_t *ptr = buf;
299 /* wait for the data request from the drive */
300 wait_drq(dev);
302 /* ready to transfer */
303 for(i=0; i<256; i++) {
304 *ptr++ = read_reg16(dev, REG_DATA);
305 }
306 }
308 static void write_data(struct device *dev, void *buf)
309 {
310 int i;
311 uint16_t *ptr = buf;
313 /* wait for the data request from the device */
314 wait_drq(dev);
316 /* ready to transfer */
317 for(i=0; i<256; i++) {
318 write_reg16(dev, REG_DATA, *ptr++);
319 }
320 }
322 static inline uint8_t read_reg8(struct device *dev, int reg)
323 {
324 uint8_t val;
325 inb(val, dev->port_base + reg);
326 return val;
327 }
329 static inline uint16_t read_reg16(struct device *dev, int reg)
330 {
331 uint16_t val;
332 inw(val, dev->port_base + reg);
333 return val;
334 }
336 static inline void write_reg8(struct device *dev, int reg, uint8_t val)
337 {
338 outb(val, dev->port_base + reg);
339 }
341 static inline void write_reg16(struct device *dev, int reg, uint16_t val)
342 {
343 outw(val, dev->port_base + reg);
344 }
346 static void ata_intr(int inum)
347 {
348 printf("ATA interrupt\n");
349 }
351 static void *atastr(void *res, void *src, int n)
352 {
353 int i;
354 uint16_t *sptr = (uint16_t*)src;
355 char *dptr = res;
357 for(i=0; i<n/2; i++) {
358 *dptr++ = (*sptr & 0xff00) >> 8;
359 *dptr++ = *sptr++ & 0xff;
360 }
362 while(isspace(*--dptr));
363 *++dptr = 0;
364 return res;
365 }
367 static char *size_str(uint64_t nsect, char *buf)
368 {
369 static const char *suffix[] = {"kb", "mb", "gb", "tb", "pb", 0};
370 int i;
371 unsigned int rem;
373 /* start with kilobytes */
374 nsect /= 2;
376 for(i=0; nsect >= 1024 && suffix[i + 1]; i++) {
377 rem = nsect % 1024;
378 nsect /= 1024;
379 }
380 sprintf(buf, "%u.%u%s", (unsigned int)nsect, 100 * rem / 1024, suffix[i]);
381 return buf;
382 }
384 #define ERR_NM (1 << 1)
385 #define ERR_ABRT (1 << 2)
386 #define ERR_MCR (1 << 3)
387 #define ERR_IDNF (1 << 4)
388 #define ERR_MC (1 << 5)
389 #define ERR_UNC (1 << 6)
391 static void print_error(int devid, int wr, uint32_t high, uint32_t low, unsigned char err)
392 {
393 printf("ata%d %s %serror ", devid, wr ? "write" : "read", err & ERR_UNC ? "uncorrectable " : "");
394 printf("at sector %x%x: ", high, low);
396 if(err & ERR_ABRT)
397 printf("abort ");
398 if(err & ERR_IDNF)
399 printf("invalid address ");
400 if(err & ERR_NM)
401 printf("no media ");
403 printf("(%x)\n", (unsigned int)err);
404 }