Implement read/write support.
[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 #define CMD_READ_SECTOR_RETRY 0x20      /* READ SECTOR with retries. */
44 #define CMD_READ_SECTOR_NORETRY 0x21    /* READ SECTOR without retries. */
45 #define CMD_WRITE_SECTOR_RETRY 0x30     /* WRITE SECTOR with retries. */
46 #define CMD_WRITE_SECTOR_NORETRY 0x31   /* WRITE SECTOR without retries. */
47
48 struct disk 
49   {
50     char name[8];
51     struct channel *channel;
52     int device;
53
54     bool is_ata;
55     disk_sector_no capacity;
56   };
57
58 struct channel 
59   {
60     char name[8];
61     uint16_t reg_base;
62     uint8_t irq;
63
64     bool expecting_interrupt;
65     struct semaphore completion_wait;
66
67     struct disk dev[2];
68   };
69
70 #define CHANNEL_CNT (sizeof channels / sizeof *channels)
71 static struct channel channels[2];
72
73 static void
74 wait_until_idle (const struct disk *d) 
75 {
76   int i;
77
78   for(i = 0; i < 1000; i++) 
79     {
80       if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
81         return;
82       timer_usleep (10);
83     }
84
85   printk ("%s: idle timeout\n", d->name);
86 }
87
88 /* Wait up to 30 seconds for disk D to clear BSY. */
89 static bool
90 wait_while_busy (const struct disk *d) 
91 {
92   struct channel *c = d->channel;
93   int i;
94   
95   for (i = 0; i < 3000; i++)
96     {
97       if (i == 700)
98         printk ("%s: busy, waiting...", d->name);
99       if (!(inb (reg_alt_status (c)) & STA_BSY)) 
100         {
101           if (i >= 700)
102             printk ("ok\n");
103           return true; 
104         }
105       timer_msleep (10);
106     }
107
108   printk ("failed\n");
109   return false;
110 }
111
112 static void
113 select_device (const struct disk *d)
114 {
115   struct channel *c = d->channel;
116   uint8_t dev = DEV_MBS;
117   if (d->device == 1)
118     dev |= DEV_DEV;
119   outb (reg_device (c), dev);
120   inb (reg_alt_status (c));
121   timer_nsleep (400);
122 }
123
124 static void
125 select_device_wait (const struct disk *d) 
126 {
127   wait_until_idle (d);
128   select_device (d);
129   wait_until_idle (d);
130 }
131
132 static void
133 reset_channel (struct channel *c) 
134 {
135   bool present[2];
136   int device;
137
138   /* The ATA reset sequence depends on which devices are present,
139      so we start by detecting device presence. */
140   for (device = 0; device < 2; device++)
141     {
142       struct disk *d = &c->dev[device];
143
144       select_device (d);
145
146       outb (reg_nsect (c), 0x55);
147       outb (reg_lbal (c), 0xaa);
148
149       outb (reg_nsect (c), 0xaa);
150       outb (reg_lbal (c), 0x55);
151
152       outb (reg_nsect (c), 0x55);
153       outb (reg_lbal (c), 0xaa);
154
155       present[device] = (inb (reg_nsect (c)) == 0x55
156                          && inb (reg_lbal (c)) == 0xaa);
157     }
158
159   /* Issue soft reset sequence, which selects device 0 as a side effect.
160      Also enable interrupts. */
161   outb (reg_ctl (c), 0);
162   timer_usleep (10);
163   outb (reg_ctl (c), CTL_SRST);
164   timer_usleep (10);
165   outb (reg_ctl (c), 0);
166
167   timer_msleep (150);
168
169   /* Wait for device 0 to clear BSY. */
170   if (present[0]) 
171     {
172       select_device (&c->dev[0]);
173       wait_while_busy (&c->dev[0]); 
174     }
175
176   /* Wait for device 1 to clear BSY. */
177   if (present[1])
178     {
179       int i;
180
181       select_device (&c->dev[1]);
182       for (i = 0; i < 3000; i++) 
183         {
184           if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
185             break;
186           timer_msleep (10);
187         }
188       wait_while_busy (&c->dev[1]);
189     }
190 }
191
192 static bool
193 check_device_type (struct disk *d) 
194 {
195   struct channel *c = d->channel;
196   uint8_t error, lbam, lbah;
197
198   select_device (d);
199
200   error = inb (reg_error (c));
201   lbam = inb (reg_lbam (c));
202   lbah = inb (reg_lbah (c));
203
204   if (error != 1 && (error != 0x81 || d->device == 1)) 
205     {
206       d->is_ata = false;
207       return error != 0x81;      
208     }
209   else 
210     {
211       d->is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
212       return true; 
213     }
214 }
215
216 static void
217 execute_command (struct disk *d, uint8_t command) 
218 {
219   struct channel *c = d->channel;
220
221   /* Interrupts must be enabled or our semaphore will never be
222      up'd by the completion handler. */
223   ASSERT (intr_get_level () == IF_ON);
224
225   /* Atomically note that we expect an interrupt and send the
226      command to the device. */
227   intr_disable ();
228   c->expecting_interrupt = true;
229   outb (reg_command (c), command);
230   intr_enable ();
231
232   /* Wait for the command to complete. */
233   sema_down (&c->completion_wait);
234 }
235
236 static bool
237 input_sector (struct channel *c, void *sector) 
238 {
239   uint8_t status;
240
241   ASSERT (sector != NULL);
242
243   status = inb (reg_status (c));
244   if (status & STA_DRQ) 
245     {
246       /* Command was successful.  Read data into SECTOR. */
247       insw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
248       return true; 
249     }
250   else 
251     {
252       /* Command failed. */
253       return false; 
254     }
255 }
256
257 static bool
258 output_sector (struct channel *c, const void *sector) 
259 {
260   uint8_t status;
261
262   ASSERT (sector != NULL);
263
264   status = inb (reg_status (c));
265   if (status & STA_DRQ) 
266     {
267       /* Command was successful.  Write data into SECTOR. */
268       outsw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
269       return true; 
270     }
271   else 
272     {
273       /* Command failed. */
274       return false; 
275     }
276 }
277
278 static void
279 printk_ata_string (char *string, size_t word_cnt) 
280 {
281   int last;
282   int i;
283
284   for (last = word_cnt * 2 - 1; last >= 0; last--)
285     if (string[last ^ 1] != ' ')
286       break;
287
288   for (i = 0; i <= last; i++)
289     printk ("%c", string[i ^ 1]);
290 }
291
292 static void
293 identify_ata_device (struct disk *d) 
294 {
295   uint16_t id[DISK_SECTOR_SIZE / 2];
296
297   ASSERT (d->is_ata);
298
299   select_device_wait (d);
300   execute_command (d, CMD_IDENTIFY);
301   wait_while_busy (d);
302
303   if (!input_sector (d->channel, id)) 
304     {
305       d->is_ata = false;
306       return;
307     }
308
309   d->capacity = id[60] | ((uint32_t) id[61] << 16);
310   printk ("%s: detected %'"PRDSNu" sector (%d MB) disk: ",
311           d->name, d->capacity, d->capacity * DISK_SECTOR_SIZE / 1024 / 1024);
312   printk_ata_string ((char *) &id[27], 20);
313   printk (" ");
314   printk_ata_string ((char *) &id[10], 10);
315   printk ("\n");
316 }
317
318 static void
319 interrupt_handler (struct intr_frame *f) 
320 {
321   struct channel *c;
322
323   for (c = channels; c < channels + CHANNEL_CNT; c++)
324     if (f->vec_no == c->irq)
325       {
326         if (c->expecting_interrupt) 
327           {
328             /* Acknowledge interrupt. */
329             inb (reg_status (c));
330
331             /* Wake up waiter. */
332             sema_up (&c->completion_wait);
333           }
334         else
335           printk ("%s: unexpected interrupt\n", c->name);
336         return;
337       }
338
339   NOT_REACHED ();
340 }
341
342 void
343 disk_init (void) 
344 {
345   size_t channel;
346
347   for (channel = 0; channel < CHANNEL_CNT; channel++)
348     {
349       struct channel *c = &channels[channel];
350       int device;
351
352       /* Initialize channel. */
353       snprintf (c->name, sizeof c->name, "ide%d", channel);
354       switch (channel) 
355         {
356         case 0:
357           c->reg_base = 0x1f0;
358           c->irq = 14 + 0x20;
359           break;
360         case 1:
361           c->reg_base = 0x170;
362           c->irq = 15 + 0x20;
363           break;
364         default:
365           NOT_REACHED ();
366         }
367       c->expecting_interrupt = false;
368       sema_init (&c->completion_wait, 0, c->name);
369  
370       /* Initialize devices. */
371       for (device = 0; device < 2; device++)
372         {
373           struct disk *d = &c->dev[device];
374           snprintf (d->name, sizeof d->name, "%s:%d", c->name, device);
375           d->channel = c;
376           d->device = device;
377
378           d->is_ata = false;
379           d->capacity = 0;
380         }
381
382       /* Register interrupt handler. */
383       intr_register (c->irq, 0, IF_OFF, interrupt_handler, c->name);
384
385       /* Reset hardware. */
386       reset_channel (c);
387
388       /* Distinguish ATA hard disks from other devices. */
389       if (check_device_type (&c->dev[0]))
390         check_device_type (&c->dev[1]);
391
392       /* Read hard disk identity information. */
393       for (device = 0; device < 2; device++)
394         if (c->dev[device].is_ata)
395           identify_ata_device (&c->dev[device]);
396     }
397 }
398
399 struct disk *
400 disk_get (int idx) 
401 {
402   struct disk *d;
403   
404   ASSERT (idx >= 0 && idx < 4);
405   d = &channels[idx / 2].dev[idx % 2];
406   return d->is_ata ? d : NULL;
407 }
408
409 disk_sector_no
410 disk_size (struct disk *d) 
411 {
412   ASSERT (d != NULL);
413   
414   return d->capacity;
415 }
416
417 static void
418 select_sector (struct disk *d, disk_sector_no sec_no) 
419 {
420   struct channel *c = d->channel;
421
422   ASSERT (sec_no < d->capacity);
423   ASSERT (sec_no < (1UL << 28));
424   
425   select_device_wait (d);
426   outb (reg_nsect (c), 1);
427   outb (reg_lbal (c), sec_no);
428   outb (reg_lbam (c), sec_no >> 8);
429   outb (reg_lbah (c), (sec_no >> 16));
430   outb (reg_device (c),
431         DEV_MBS | DEV_LBA | (d->device == 1 ? DEV_DEV : 0) | (sec_no >> 24));
432 }
433
434 void
435 disk_read (struct disk *d, disk_sector_no sec_no, void *buffer) 
436 {
437   ASSERT (d != NULL);
438   ASSERT (buffer != NULL);
439
440   select_sector (d, sec_no);
441   execute_command (d, CMD_READ_SECTOR_RETRY);
442   wait_while_busy (d);
443   if (!input_sector (d->channel, buffer))
444     panic ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no);
445 }
446
447 void
448 disk_write (struct disk *d, disk_sector_no sec_no, const void *buffer)
449 {
450   ASSERT (d != NULL);
451   ASSERT (buffer != NULL);
452
453   select_sector (d, sec_no);
454   execute_command (d, CMD_WRITE_SECTOR_RETRY);
455   wait_while_busy (d);
456   if (!output_sector (d->channel, buffer))
457     panic ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no);
458 }