Initial un-working code.
[pintos-anon] / src / devices / disk.c
1 #include "disk.h"
2
3 #define reg_data(CHANNEL) ((CHANNEL)->reg_base + 0)
4 #define reg_error(CHANNEL) ((CHANNEL)->reg_base + 1)
5 #define reg_nsect(CHANNEL) ((CHANNEL)->reg_base + 2)
6 #define reg_lbal(CHANNEL) ((CHANNEL)->reg_base + 3)
7 #define reg_lbam(CHANNEL) ((CHANNEL)->reg_base + 4)
8 #define reg_lbah(CHANNEL) ((CHANNEL)->reg_base + 5)
9 #define reg_device(CHANNEL) ((CHANNEL)->reg_base + 6)
10 #define reg_status(CHANNEL) ((CHANNEL)->reg_base + 7)
11 #define reg_command(CHANNEL) reg_status (CHANNEL)
12 #define reg_ctl(CHANNEL) ((CHANNEL)->reg_base + 0x206)
13 #define reg_alt(CHANNEL) reg_ctl (CHANNEL)
14
15 /* Alternate Status Register bits. */
16 #define ALT_BSY 0x80
17 #define ALT_DRDY 0x40
18 #define ALT_DF 0x20
19 #define ALT_DSC 0x10
20 #define ALT_DRQ 0x08
21 #define ALT_CORR 0x04
22 #define ALT_IDX 0x02
23 #define ALT_ERR 0x01
24
25 /* Control Register bits. */
26 #define CTL_SRST 0x04
27 #define CTL_NIEN 0x02
28
29 /* Device Register bits. */
30 #define DEV_MBS 0xa0            /* Must be set. */
31 #define DEV_LBA 0x40            /* Linear based addressing. */
32 #define DEV_DEV 0x10            /* Select device: 0=master, 1=slave. */
33
34 /* Commands. */
35 #define CMD_IDENTIFY 0xec       /* IDENTIFY DEVICE. */
36
37 struct disk 
38   {
39     const char *name;
40     struct channel *channel;
41     int device;
42
43     bool is_ata;
44     disk_sector_no capacity;
45   };
46
47 struct channel 
48   {
49     const char *name;
50     uint16_t reg_base;
51     int irq;
52     struct disk dev[2];
53   };
54
55 #define CHANNEL_CNT (sizeof channels / sizeof *channels)
56 static struct channel channels[2] = {
57   {"ide0", 0x1f0, 14},
58   {"ide1", 0x170, 15},
59 };
60
61 static void
62 select_device (struct device *d) 
63 {
64   struct channel *c = d->channel;
65   uint8_t dev = DEV_MBS;
66   if (d->device == 1)
67     dev |= DEV_DEV;
68   outb (reg_device (c), dev);
69   inb (reg_alt (c));
70   ndelay (400);
71 }
72
73 static void
74 wait_idle (struct device *d) 
75 {
76   int i;
77
78   for(i = 0; i < 1000; i++) 
79     {
80       if ((inb (reg_status (d->channel)) & (STA_BUSY | STA_DRQ)) == 0)
81         return;
82       udelay (10);
83     }
84
85   printk ("%s: idle timeout\n", d->name);
86 }
87
88 static void
89 select_device_wait (struct device *d) 
90 {
91   wait_idle (d);
92   select_device (d);
93   wait_idle (d);
94 }
95
96 static bool
97 busy_wait (struct channel *c) 
98 {
99   int i;
100   
101   for (i = 0; i < 3000; i++)
102     {
103       if (i == 700)
104         printk ("%s: busy, waiting...");
105       if (!(inb (reg_alt (c)) & ALT_BSY)) 
106         {
107           if (i >= 700)
108             printk ("ok\n");
109           return true; 
110         }
111       mdelay (10);
112     }
113
114   printk ("failed\n", c->name);
115   return false;
116 }
117
118 static void
119 reset_channel (struct channel *c) 
120 {
121   bool present[2];
122
123   /* The ATA reset sequence depends on which devices are present,
124      so we start by detecting device presence. */
125   for (device = 0; device < 2; device++)
126     {
127       struct disk *d = &c->dev[device];
128       
129       select_device (d);
130
131       outb (reg_nsect (c), 0x55);
132       outb (reg_lbal (c), 0xaa);
133
134       outb (reg_nsect (c), 0xaa);
135       outb (reg_lbal (c), 0x55);
136
137       outb (reg_nsect (c), 0x55);
138       outb (reg_lbal (c), 0xaa);
139
140       present[device] = (inb (reg_nsect (c)) == 0x55
141                          && inb (reg_lbal (c)) == 0xaa);
142     }
143
144   /* Issue soft reset sequence, which selects device 0 as a side effect.
145      Also enable interrupts. */
146   outb (reg_ctl (c), 0);
147   delay (1);
148   outb (reg_ctl (c), CTL_SRST);
149   delay (1);
150   outb (reg_ctl (c), 0);
151   delay (150);
152
153   /* Wait for device 0 to clear BSY. */
154   if (present[0]) 
155     {
156       select_device (c->dev[0]);
157       busy_wait (c); 
158     }
159
160   /* Wait for device 1 to clear BSY. */
161   if (present[1])
162     {
163       select_device (c->dev[1]);
164       for (i = 0; i < 3000; i++) 
165         {
166           if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
167             break;
168           delay (10);
169         }
170       busy_wait (c);
171     }
172 }
173
174 static bool
175 check_ata_device (const struct device *d) 
176 {
177   struct channel *c = d->channel;
178   bool maybe_slave;     /* If D is a master, could a slave exist? */
179   uint8_t error, lbam, lbah;
180
181   select_device (d);
182
183   error = inb (reg_error (c));
184   lbam = inb (reg_lbam (c));
185   lbah = inb (reg_lbah (c));
186
187   if (error != 1 && (error != 0x81 || d->device == 1)) 
188     {
189       d->is_ata = false;
190       return error != 0x81;      
191     }
192   else 
193     {
194       d->is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
195       return true; 
196     }
197 }
198
199 static void
200 execute_command (struct disk *d, uint8_t command) 
201 {
202   struct channel *c = d->channel;
203
204   /* Interrupts must be enabled or our semaphore will never be
205      up'd by the completion handler. */
206   ASSERT (intr_get_level () == IF_ON);
207
208   intr_disable ();
209   sema_init (&completion_sema, 0, "disk");
210   intr_enable ();
211   
212   outb (reg_command (c), command);
213
214   sema_down ();
215 }
216
217 void
218 identify_ata_device (struct disk *d) 
219 {
220   struct channel *c = d->channel;
221
222   ASSERT (d->is_ata);
223
224   select_device_wait (d);
225   execute_command (CMD_IDENTIFY);
226   
227   
228
229 }
230
231 void
232 disk_init (void) 
233 {
234   struct channel *c;
235
236   for (c = channels; c < channels + CHANNEL_CNT; c++)
237     {
238       int device;
239
240       /* Register interrupt handler. */
241       register_irq (c);
242
243       /* Initialize device state. */
244       for (device = 0; device < 2; device++)
245         {
246           struct disk *d = &c->dev[device];
247           d->channel = c;
248           d->device = device;
249         }
250
251       /* Reset hardware. */
252       reset_channel (c);
253
254       /* Detect ATA devices. */
255       if (check_ata_device (&c->dev[0]))
256         check_ata_device (&c->dev[1]);
257
258       /* Detect device properties. */
259       for (device = 0; device < 2; device++)
260         if (c->dev[device].is_ata)
261           identify_ata_device (&c->dev[device]);
262     }
263 }
264
265 struct disk *
266 disk_get (int idx) 
267 {
268   ASSERT (idx >= 0 && idx < 4);
269   return &channel[idx / 2].dev[idx % 2];
270 }
271
272 disk_sector_no disk_size (struct disk *);
273 void disk_read (struct disk *, disk_sector_no, void *);
274 void disk_write (struct disk *, disk_sector_no, const void *);