Better ID message. Add per-channel mutual exclusion.
[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 execute_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   /* Wait for the command to complete. */
234   sema_down (&c->completion_wait);
235 }
236
237 static bool
238 input_sector (struct channel *c, void *sector) 
239 {
240   uint8_t status;
241
242   ASSERT (sector != NULL);
243
244   status = inb (reg_status (c));
245   if (status & STA_DRQ) 
246     {
247       /* Command was successful.  Read data into SECTOR. */
248       insw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
249       return true; 
250     }
251   else 
252     {
253       /* Command failed. */
254       return false; 
255     }
256 }
257
258 static bool
259 output_sector (struct channel *c, const void *sector) 
260 {
261   uint8_t status;
262
263   ASSERT (sector != NULL);
264
265   status = inb (reg_status (c));
266   if (status & STA_DRQ) 
267     {
268       /* Command was successful.  Write data into SECTOR. */
269       outsw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
270       return true; 
271     }
272   else 
273     {
274       /* Command failed. */
275       return false; 
276     }
277 }
278
279 static void
280 printk_ata_string (char *string, size_t word_cnt) 
281 {
282   int last;
283   int i;
284
285   for (last = word_cnt * 2 - 1; last >= 0; last--)
286     if (string[last ^ 1] != ' ')
287       break;
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   execute_command (d, CMD_IDENTIFY);
302   wait_while_busy (d);
303
304   if (!input_sector (d->channel, id)) 
305     {
306       d->is_ata = false;
307       return;
308     }
309
310   /* Calculate capacity. */
311   d->capacity = id[60] | ((uint32_t) id[61] << 16);
312
313   /* Print identification message. */
314   printk ("%s: detected %'"PRDSNu" sector (", d->name, d->capacity);
315   if (d->capacity > 1024 / DISK_SECTOR_SIZE * 1024 * 1024)
316     printk ("%"PRDSNu" GB",
317             d->capacity / (1024 / DISK_SECTOR_SIZE * 1024 * 1024));
318   else if (d->capacity > 1024 / DISK_SECTOR_SIZE * 1024)
319     printk ("%"PRDSNu" MB", d->capacity / (1024 / DISK_SECTOR_SIZE * 1024));
320   else if (d->capacity > 1024 / DISK_SECTOR_SIZE)
321     printk ("%"PRDSNu" kB", d->capacity / (1024 / DISK_SECTOR_SIZE));
322   else
323     printk ("%"PRDSNu" byte", d->capacity * DISK_SECTOR_SIZE);
324   printk (") disk \"");
325   printk_ata_string ((char *) &id[27], 20);
326   printk (" ");
327   printk_ata_string ((char *) &id[10], 10);
328   printk ("\"\n");
329 }
330
331 static void
332 interrupt_handler (struct intr_frame *f) 
333 {
334   struct channel *c;
335
336   for (c = channels; c < channels + CHANNEL_CNT; c++)
337     if (f->vec_no == c->irq)
338       {
339         if (c->expecting_interrupt) 
340           {
341             /* Acknowledge interrupt. */
342             inb (reg_status (c));
343
344             /* Wake up waiter. */
345             sema_up (&c->completion_wait);
346           }
347         else
348           printk ("%s: unexpected interrupt\n", c->name);
349         return;
350       }
351
352   NOT_REACHED ();
353 }
354
355 void
356 disk_init (void) 
357 {
358   size_t channel;
359
360   for (channel = 0; channel < CHANNEL_CNT; channel++)
361     {
362       struct channel *c = &channels[channel];
363       int device;
364
365       /* Initialize channel. */
366       snprintf (c->name, sizeof c->name, "ide%d", channel);
367       switch (channel) 
368         {
369         case 0:
370           c->reg_base = 0x1f0;
371           c->irq = 14 + 0x20;
372           break;
373         case 1:
374           c->reg_base = 0x170;
375           c->irq = 15 + 0x20;
376           break;
377         default:
378           NOT_REACHED ();
379         }
380       lock_init (&c->lock, c->name);
381       c->expecting_interrupt = false;
382       sema_init (&c->completion_wait, 0, c->name);
383  
384       /* Initialize devices. */
385       for (device = 0; device < 2; device++)
386         {
387           struct disk *d = &c->dev[device];
388           snprintf (d->name, sizeof d->name, "%s:%d", c->name, device);
389           d->channel = c;
390           d->device = device;
391
392           d->is_ata = false;
393           d->capacity = 0;
394         }
395
396       /* Register interrupt handler. */
397       intr_register (c->irq, 0, IF_OFF, interrupt_handler, c->name);
398
399       /* Reset hardware. */
400       reset_channel (c);
401
402       /* Distinguish ATA hard disks from other devices. */
403       if (check_device_type (&c->dev[0]))
404         check_device_type (&c->dev[1]);
405
406       /* Read hard disk identity information. */
407       for (device = 0; device < 2; device++)
408         if (c->dev[device].is_ata)
409           identify_ata_device (&c->dev[device]);
410     }
411 }
412
413 struct disk *
414 disk_get (int idx) 
415 {
416   struct disk *d;
417   
418   ASSERT (idx >= 0 && idx < 4);
419   d = &channels[idx / 2].dev[idx % 2];
420   return d->is_ata ? d : NULL;
421 }
422
423 disk_sector_no
424 disk_size (struct disk *d) 
425 {
426   ASSERT (d != NULL);
427   
428   return d->capacity;
429 }
430
431 static void
432 select_sector (struct disk *d, disk_sector_no sec_no) 
433 {
434   struct channel *c = d->channel;
435
436   ASSERT (sec_no < d->capacity);
437   ASSERT (sec_no < (1UL << 28));
438   
439   select_device_wait (d);
440   outb (reg_nsect (c), 1);
441   outb (reg_lbal (c), sec_no);
442   outb (reg_lbam (c), sec_no >> 8);
443   outb (reg_lbah (c), (sec_no >> 16));
444   outb (reg_device (c),
445         DEV_MBS | DEV_LBA | (d->device == 1 ? DEV_DEV : 0) | (sec_no >> 24));
446 }
447
448 void
449 disk_read (struct disk *d, disk_sector_no sec_no, void *buffer) 
450 {
451   ASSERT (d != NULL);
452   ASSERT (buffer != NULL);
453
454   lock_acquire (&d->channel->lock);
455   select_sector (d, sec_no);
456   execute_command (d, CMD_READ_SECTOR_RETRY);
457   wait_while_busy (d);
458   if (!input_sector (d->channel, buffer))
459     panic ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no);
460 }
461
462 void
463 disk_write (struct disk *d, disk_sector_no sec_no, const void *buffer)
464 {
465   ASSERT (d != NULL);
466   ASSERT (buffer != NULL);
467
468   lock_acquire (&d->channel->lock);
469   select_sector (d, sec_no);
470   execute_command (d, CMD_WRITE_SECTOR_RETRY);
471   wait_while_busy (d);
472   if (!output_sector (d->channel, buffer))
473     panic ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no);
474   lock_release (&d->channel->lock);
475 }