Basic disk detection stuff.
[pintos-anon] / src / devices / disk.c
1 #include "disk.h"
2 #include <stdbool.h>
3 #include "debug.h"
4 #include "io.h"
5 #include "interrupt.h"
6 #include "lib.h"
7 #include "synch.h"
8 #include "timer.h"
9
10 #define reg_data(CHANNEL) ((CHANNEL)->reg_base + 0)
11 #define reg_error(CHANNEL) ((CHANNEL)->reg_base + 1)
12 #define reg_nsect(CHANNEL) ((CHANNEL)->reg_base + 2)
13 #define reg_lbal(CHANNEL) ((CHANNEL)->reg_base + 3)
14 #define reg_lbam(CHANNEL) ((CHANNEL)->reg_base + 4)
15 #define reg_lbah(CHANNEL) ((CHANNEL)->reg_base + 5)
16 #define reg_device(CHANNEL) ((CHANNEL)->reg_base + 6)
17 #define reg_status(CHANNEL) ((CHANNEL)->reg_base + 7)
18 #define reg_command(CHANNEL) reg_status (CHANNEL)
19 #define reg_ctl(CHANNEL) ((CHANNEL)->reg_base + 0x206)
20 #define reg_alt_status(CHANNEL) reg_ctl (CHANNEL)
21
22 /* Alternate Status Register bits. */
23 #define STA_BSY 0x80
24 #define STA_DRDY 0x40
25 #define STA_DF 0x20
26 #define STA_DSC 0x10
27 #define STA_DRQ 0x08
28 #define STA_CORR 0x04
29 #define STA_IDX 0x02
30 #define STA_ERR 0x01
31
32 /* Control Register bits. */
33 #define CTL_SRST 0x04
34 #define CTL_NIEN 0x02
35
36 /* Device Register bits. */
37 #define DEV_MBS 0xa0            /* Must be set. */
38 #define DEV_LBA 0x40            /* Linear based addressing. */
39 #define DEV_DEV 0x10            /* Select device: 0=master, 1=slave. */
40
41 /* Commands. */
42 #define CMD_IDENTIFY 0xec       /* IDENTIFY DEVICE. */
43
44 struct disk 
45   {
46     char name[8];
47     struct channel *channel;
48     int device;
49
50     bool is_ata;
51     disk_sector_no capacity;
52   };
53
54 struct channel 
55   {
56     char name[8];
57     uint16_t reg_base;
58     uint8_t irq;
59
60     bool expecting_interrupt;
61     struct semaphore completion_wait;
62
63     struct disk dev[2];
64   };
65
66 #define CHANNEL_CNT (sizeof channels / sizeof *channels)
67 static struct channel channels[2];
68
69 static void
70 select_device (const struct disk *d)
71 {
72   struct channel *c = d->channel;
73   uint8_t dev = DEV_MBS;
74   if (d->device == 1)
75     dev |= DEV_DEV;
76   outb (reg_device (c), dev);
77   inb (reg_alt_status (c));
78   timer_nsleep (400);
79 }
80
81 static void
82 wait_idle (const struct disk *d) 
83 {
84   int i;
85
86   for(i = 0; i < 1000; i++) 
87     {
88       if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
89         return;
90       timer_usleep (10);
91     }
92
93   printk ("%s: idle timeout\n", d->name);
94 }
95
96 static void
97 select_device_wait (const struct disk *d) 
98 {
99   wait_idle (d);
100   select_device (d);
101   wait_idle (d);
102 }
103
104 /* Wait up to 30 seconds for disk D to clear BSY. */
105 static bool
106 busy_wait (const struct disk *d) 
107 {
108   struct channel *c = d->channel;
109   int i;
110   
111   for (i = 0; i < 3000; i++)
112     {
113       if (i == 700)
114         printk ("%s: busy, waiting...", d->name);
115       if (!(inb (reg_alt_status (c)) & STA_BSY)) 
116         {
117           if (i >= 700)
118             printk ("ok\n");
119           return true; 
120         }
121       timer_msleep (10);
122     }
123
124   printk ("failed\n");
125   return false;
126 }
127
128 static void
129 reset_channel (struct channel *c) 
130 {
131   bool present[2];
132   int device;
133
134   /* The ATA reset sequence depends on which devices are present,
135      so we start by detecting device presence. */
136   for (device = 0; device < 2; device++)
137     {
138       struct disk *d = &c->dev[device];
139
140       select_device (d);
141
142       outb (reg_nsect (c), 0x55);
143       outb (reg_lbal (c), 0xaa);
144
145       outb (reg_nsect (c), 0xaa);
146       outb (reg_lbal (c), 0x55);
147
148       outb (reg_nsect (c), 0x55);
149       outb (reg_lbal (c), 0xaa);
150
151       present[device] = (inb (reg_nsect (c)) == 0x55
152                          && inb (reg_lbal (c)) == 0xaa);
153     }
154
155   /* Issue soft reset sequence, which selects device 0 as a side effect.
156      Also enable interrupts. */
157   outb (reg_ctl (c), 0);
158   timer_usleep (10);
159   outb (reg_ctl (c), CTL_SRST);
160   timer_usleep (10);
161   outb (reg_ctl (c), 0);
162
163   timer_msleep (150);
164
165   /* Wait for device 0 to clear BSY. */
166   if (present[0]) 
167     {
168       select_device (&c->dev[0]);
169       busy_wait (&c->dev[0]); 
170     }
171
172   /* Wait for device 1 to clear BSY. */
173   if (present[1])
174     {
175       int i;
176
177       select_device (&c->dev[1]);
178       for (i = 0; i < 3000; i++) 
179         {
180           if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
181             break;
182           timer_msleep (10);
183         }
184       busy_wait (&c->dev[1]);
185     }
186 }
187
188 static bool
189 check_ata_device (struct disk *d) 
190 {
191   struct channel *c = d->channel;
192   uint8_t error, lbam, lbah;
193
194   select_device (d);
195
196   error = inb (reg_error (c));
197   lbam = inb (reg_lbam (c));
198   lbah = inb (reg_lbah (c));
199
200   if (error != 1 && (error != 0x81 || d->device == 1)) 
201     {
202       d->is_ata = false;
203       return error != 0x81;      
204     }
205   else 
206     {
207       d->is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
208       return true; 
209     }
210 }
211
212 static void
213 execute_command (struct disk *d, uint8_t command) 
214 {
215   struct channel *c = d->channel;
216
217   /* Interrupts must be enabled or our semaphore will never be
218      up'd by the completion handler. */
219   ASSERT (intr_get_level () == IF_ON);
220
221   /* Atomically note that we expect an interrupt and send the
222      command to the device. */
223   intr_disable ();
224   c->expecting_interrupt = true;
225   outb (reg_command (c), command);
226   intr_enable ();
227
228   /* Wait for the command to complete. */
229   sema_down (&c->completion_wait);
230 }
231
232 static bool
233 input_sector (struct channel *c, void *sector) 
234 {
235   uint8_t status;
236
237   ASSERT (sector != NULL);
238
239   status = inb (reg_status (c));
240   if (status & STA_DRQ) 
241     {
242       /* Command was successful.  Read data into SECTOR. */
243       insw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
244       return true; 
245     }
246   else 
247     {
248       /* Command failed. */
249       return false; 
250     }
251 }
252
253 static void
254 identify_ata_device (struct disk *d) 
255 {
256   uint16_t id[DISK_SECTOR_SIZE / 2];
257
258   ASSERT (d->is_ata);
259
260   select_device_wait (d);
261   execute_command (d, CMD_IDENTIFY);
262   busy_wait (d);
263
264   if (!input_sector (d->channel, id)) 
265     {
266       d->is_ata = false;
267       return;
268     }
269
270   d->capacity = id[57] | ((uint32_t) id[58] << 16);
271   printk ("%s: detected %"PRDSNu" sector (%d MB) disk\n",
272           d->name, d->capacity, d->capacity * DISK_SECTOR_SIZE / 1024 / 1024);
273 }
274
275 static void
276 interrupt_handler (struct intr_frame *f) 
277 {
278   struct channel *c;
279
280   for (c = channels; c < channels + CHANNEL_CNT; c++)
281     if (f->vec_no == c->irq)
282       {
283         if (c->expecting_interrupt) 
284           sema_up (&c->completion_wait);
285         else
286           printk ("%s: unexpected interrupt\n", c->name);
287         return;
288       }
289
290   NOT_REACHED ();
291 }
292
293 void
294 disk_init (void) 
295 {
296   size_t channel;
297
298   for (channel = 0; channel < CHANNEL_CNT; channel++)
299     {
300       struct channel *c = &channels[channel];
301       int device;
302
303       /* Initialize channel. */
304       snprintf (c->name, sizeof c->name, "ide%d", channel);
305       switch (channel) 
306         {
307         case 0:
308           c->reg_base = 0x1f0;
309           c->irq = 14 + 0x20;
310           break;
311         case 1:
312           c->reg_base = 0x170;
313           c->irq = 15 + 0x20;
314           break;
315         default:
316           NOT_REACHED ();
317         }
318       c->expecting_interrupt = false;
319       sema_init (&c->completion_wait, 0, c->name);
320  
321       /* Initialize devices. */
322       for (device = 0; device < 2; device++)
323         {
324           struct disk *d = &c->dev[device];
325           snprintf (d->name, sizeof d->name, "%s:%d", c->name, device);
326           d->channel = c;
327           d->device = device;
328
329           d->is_ata = false;
330           d->capacity = 0;
331         }
332
333       /* Register interrupt handler. */
334       intr_register (c->irq, 0, IF_OFF, interrupt_handler, c->name);
335
336       /* Reset hardware. */
337       reset_channel (c);
338
339       /* Detect ATA devices. */
340       if (check_ata_device (&c->dev[0]))
341         check_ata_device (&c->dev[1]);
342
343       /* Detect device properties. */
344       for (device = 0; device < 2; device++)
345         if (c->dev[device].is_ata)
346           identify_ata_device (&c->dev[device]);
347     }
348 }
349
350 struct disk *
351 disk_get (int idx) 
352 {
353   ASSERT (idx >= 0 && idx < 4);
354   return &channels[idx / 2].dev[idx % 2];
355 }
356
357 disk_sector_no disk_size (struct disk *);
358 void disk_read (struct disk *, disk_sector_no, void *);
359 void disk_write (struct disk *, disk_sector_no, const void *);