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