kern

view src/ata.c @ 80:4db99a52863e

fixed the "endianess" of the text messages in the ATA identify info block. this is the first time I've seen wrong byteorder in ascii text, the ATA committee should be commended.
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 06 Dec 2011 13:35:39 +0200
parents 251a65b62223
children 9c979413cfbf
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5 #include <assert.h>
6 #include "ata.h"
7 #include "intr.h"
8 #include "asmops.h"
10 /* registers */
11 #define REG_DATA 0 /* R/W */
12 #define REG_ERROR 1 /* R */
13 #define REG_FEATURES 1 /* W */
14 #define REG_COUNT 2 /* R/W */
15 #define REG_LBA0 3 /* R/W */
16 #define REG_LBA1 4 /* R/W */
17 #define REG_LBA2 5 /* R/W */
18 #define REG_DEVICE 6 /* R/W */
19 #define REG_CMD 7 /* W */
20 #define REG_STATUS 7 /* R */
22 #define REG_CTL 518
23 #define REG_ALTSTAT 518
25 /* status bit fields */
26 #define ST_ERR (1 << 0)
27 #define ST_DRQ (1 << 3)
28 #define ST_DRDY (1 << 6)
29 #define ST_BSY (1 << 7)
31 /* device select bit in control register */
32 #define DEV_SEL(x) (((x) & 1) << 4)
34 /* ATA commands */
35 #define CMD_IDENTIFY 0xec
38 struct device {
39 int id; /* id of the device on its ATA interface (0 master, 1 slave) */
40 int iface; /* ATA interface for this device (0 or 1) */
41 int port_base; /* interface I/O port base */
43 uint32_t nsect_lba;
44 uint64_t nsect_lba48;
45 };
48 static int identify(struct device *dev, int iface, int id);
49 static void select_dev(struct device *dev);
50 static int wait_busy(struct device *dev);
51 static int wait_drq(struct device *dev);
52 static void read_data(struct device *dev, void *buf);
53 static inline uint8_t read_reg8(struct device *dev, int reg);
54 static inline uint16_t read_reg16(struct device *dev, int reg);
55 static inline void write_reg8(struct device *dev, int reg, uint8_t val);
56 static inline void write_reg16(struct device *dev, int reg, uint16_t val);
57 static void ata_intr(int inum);
58 static void *atastr(void *res, void *src, int n);
59 static char *size_str(uint64_t nsect, char *buf);
61 /* last drive selected on each bus */
62 static int drvsel[2] = {-1, -1};
64 /* 4 possible devices: 2 ATA interfaces with 2 devices each.
65 * this will never change unless we start querying the PCI config space
66 * for additional drives (in which case this whole init code must be
67 * rewritten anyway), but I like it spelt out like this.
68 */
69 #define MAX_IFACES 2
70 #define MAX_DEV (MAX_IFACES * 2)
71 static struct device dev[MAX_DEV];
74 void init_ata(void)
75 {
76 int i;
78 interrupt(IRQ_TO_INTR(15), ata_intr);
80 for(i=0; i<MAX_DEV; i++) {
81 int iface = i / MAX_IFACES;
82 int id = i % MAX_IFACES;
84 if(identify(dev + i, iface, id) == -1) {
85 dev[i].id = -1;
86 }
87 }
88 }
90 static int identify(struct device *dev, int iface, int id)
91 {
92 /* base address of the two ATA interfaces */
93 static const int port_base[] = {0x1f0, 0x170};
94 unsigned char st;
95 uint16_t *info;
96 char textbuf[42]; /* at most we need 40 chars for ident strings */
98 dev->id = id;
99 dev->iface = iface;
100 dev->port_base = port_base[iface];
102 /* a status of 0xff means there's no drive on the interface */
103 if((st = read_reg8(dev, REG_ALTSTAT)) == 0xff) {
104 return -1;
105 }
107 select_dev(dev);
108 /* wait a bit to allow the device time to respond */
109 iodelay(); iodelay(); iodelay(); iodelay();
111 write_reg8(dev, REG_CMD, CMD_IDENTIFY);
113 if(!(st = read_reg8(dev, REG_ALTSTAT)) || (st & ST_ERR)) {
114 /* does not exist */
115 return -1;
116 }
117 if(wait_busy(dev) == -1) {
118 /* got ST_ERR, not ATA */
119 return -1;
120 }
122 info = malloc(512);
123 assert(info);
125 /* read the device information */
126 read_data(dev, info);
128 /* print model and serial */
129 printf("- found ata drive (%d,%d): %s\n", dev->iface, dev->id, atastr(textbuf, info + 27, 40));
130 printf(" s/n: %s\n", atastr(textbuf, info + 10, 20));
132 dev->nsect_lba = *(uint32_t*)(info + 60);
133 dev->nsect_lba48 = *(uint64_t*)(info + 100) & 0xffffffffffffull;
135 if(!dev->nsect_lba) {
136 printf(" drive does not support LBA, ignoring!\n");
137 free(info);
138 return -1;
139 }
141 if(dev->nsect_lba48) {
142 size_str(dev->nsect_lba48, textbuf);
143 } else {
144 size_str(dev->nsect_lba, textbuf);
145 }
146 printf(" size: %s\n", textbuf);
148 free(info);
149 return 0;
150 }
152 static void select_dev(struct device *dev)
153 {
154 /* if this is the currently selected device, thy work is done */
155 if(drvsel[dev->iface] == dev->id)
156 return;
158 /* wait for BSY and DRQ to clear */
159 while(read_reg8(dev, REG_ALTSTAT) & (ST_BSY | ST_DRQ));
161 /* set the correct device bit to the device register */
162 write_reg8(dev, REG_DEVICE, DEV_SEL(dev->id));
163 }
165 static int wait_busy(struct device *dev)
166 {
167 unsigned char st;
169 do {
170 st = read_reg8(dev, REG_ALTSTAT);
171 } while((st & ST_BSY) && !(st & ST_ERR));
173 return st & ST_ERR ? -1 : 0;
174 }
176 static int wait_drq(struct device *dev)
177 {
178 unsigned char st;
180 do {
181 st = read_reg8(dev, REG_ALTSTAT);
182 } while(!(st & (ST_DRQ | ST_ERR)));
184 return st & ST_ERR ? -1 : 0;
185 }
187 static void read_data(struct device *dev, void *buf)
188 {
189 int i;
190 uint16_t *ptr = buf;
192 /* wait for the data request from the drive */
193 wait_drq(dev);
195 /* ready to transfer */
196 for(i=0; i<256; i++) {
197 *ptr++ = read_reg16(dev, REG_DATA);
198 }
199 }
201 static inline uint8_t read_reg8(struct device *dev, int reg)
202 {
203 uint8_t val;
204 inb(val, dev->port_base + reg);
205 return val;
206 }
208 static inline uint16_t read_reg16(struct device *dev, int reg)
209 {
210 uint16_t val;
211 inw(val, dev->port_base + reg);
212 return val;
213 }
215 static inline void write_reg8(struct device *dev, int reg, uint8_t val)
216 {
217 outb(val, dev->port_base + reg);
218 }
220 static inline void write_reg16(struct device *dev, int reg, uint16_t val)
221 {
222 outw(val, dev->port_base + reg);
223 }
225 static void ata_intr(int inum)
226 {
227 printf("ATA interrupt\n");
228 }
230 static void *atastr(void *res, void *src, int n)
231 {
232 int i;
233 uint16_t *sptr = (uint16_t*)src;
234 char *dptr = res;
236 for(i=0; i<n/2; i++) {
237 *dptr++ = (*sptr & 0xff00) >> 8;
238 *dptr++ = *sptr++ & 0xff;
239 }
240 *dptr = 0;
241 return res;
242 }
244 static char *size_str(uint64_t nsect, char *buf)
245 {
246 static const char *suffix[] = {"kb", "mb", "gb", "tb", "pb", 0};
247 int i;
249 /* start with kilobytes */
250 nsect /= 2;
252 for(i=0; nsect >= 1024 && suffix[i + 1]; i++) {
253 nsect /= 1024;
254 }
255 sprintf(buf, "%u %s", (unsigned int)nsect, suffix[i]);
256 return buf;
257 }