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)
22 /* Alternate Status Register bits. */
32 /* Control Register bits. */
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. */
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. */
51 struct channel *channel;
55 disk_sector_no capacity;
65 bool expecting_interrupt;
66 struct semaphore completion_wait;
71 #define CHANNEL_CNT (sizeof channels / sizeof *channels)
72 static struct channel channels[2];
75 wait_until_idle (const struct disk *d)
79 for(i = 0; i < 1000; i++)
81 if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
86 printk ("%s: idle timeout\n", d->name);
89 /* Wait up to 30 seconds for disk D to clear BSY. */
91 wait_while_busy (const struct disk *d)
93 struct channel *c = d->channel;
96 for (i = 0; i < 3000; i++)
99 printk ("%s: busy, waiting...", d->name);
100 if (!(inb (reg_alt_status (c)) & STA_BSY))
114 select_device (const struct disk *d)
116 struct channel *c = d->channel;
117 uint8_t dev = DEV_MBS;
120 outb (reg_device (c), dev);
121 inb (reg_alt_status (c));
126 select_device_wait (const struct disk *d)
134 reset_channel (struct channel *c)
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++)
143 struct disk *d = &c->dev[device];
147 outb (reg_nsect (c), 0x55);
148 outb (reg_lbal (c), 0xaa);
150 outb (reg_nsect (c), 0xaa);
151 outb (reg_lbal (c), 0x55);
153 outb (reg_nsect (c), 0x55);
154 outb (reg_lbal (c), 0xaa);
156 present[device] = (inb (reg_nsect (c)) == 0x55
157 && inb (reg_lbal (c)) == 0xaa);
160 /* Issue soft reset sequence, which selects device 0 as a side effect.
161 Also enable interrupts. */
162 outb (reg_ctl (c), 0);
164 outb (reg_ctl (c), CTL_SRST);
166 outb (reg_ctl (c), 0);
170 /* Wait for device 0 to clear BSY. */
173 select_device (&c->dev[0]);
174 wait_while_busy (&c->dev[0]);
177 /* Wait for device 1 to clear BSY. */
182 select_device (&c->dev[1]);
183 for (i = 0; i < 3000; i++)
185 if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
189 wait_while_busy (&c->dev[1]);
194 check_device_type (struct disk *d)
196 struct channel *c = d->channel;
197 uint8_t error, lbam, lbah;
201 error = inb (reg_error (c));
202 lbam = inb (reg_lbam (c));
203 lbah = inb (reg_lbah (c));
205 if (error != 1 && (error != 0x81 || d->device == 1))
208 return error != 0x81;
212 d->is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
218 issue_command (struct disk *d, uint8_t command)
220 struct channel *c = d->channel;
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);
226 /* Atomically note that we expect an interrupt and send the
227 command to the device. */
229 c->expecting_interrupt = true;
230 outb (reg_command (c), command);
235 input_sector (struct channel *c, void *sector)
239 ASSERT (sector != NULL);
241 status = inb (reg_status (c));
242 if (status & STA_DRQ)
244 /* Command was successful. Read data into SECTOR. */
245 insw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
250 /* Command failed. */
256 output_sector (struct channel *c, const void *sector)
260 ASSERT (sector != NULL);
262 status = inb (reg_status (c));
263 if (status & STA_DRQ)
265 /* Command was successful. Write data into SECTOR. */
266 outsw (reg_data (c), sector, DISK_SECTOR_SIZE / 2);
271 /* Command failed. */
277 printk_ata_string (char *string, size_t word_cnt)
282 for (last = word_cnt * 2 - 1; last >= 0; last--)
284 int c = string[last ^ 1];
285 if (c != '\0' && !isspace (c))
289 for (i = 0; i <= last; i++)
290 printk ("%c", string[i ^ 1]);
294 identify_ata_device (struct disk *d)
296 uint16_t id[DISK_SECTOR_SIZE / 2];
300 select_device_wait (d);
301 issue_command (d, CMD_IDENTIFY);
302 sema_down (&d->channel->completion_wait);
305 if (!input_sector (d->channel, id))
311 /* Calculate capacity. */
312 d->capacity = id[60] | ((uint32_t) id[61] << 16);
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));
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);
333 interrupt_handler (struct intr_frame *f)
337 for (c = channels; c < channels + CHANNEL_CNT; c++)
338 if (f->vec_no == c->irq)
340 if (c->expecting_interrupt)
342 /* Acknowledge interrupt. */
343 inb (reg_status (c));
345 /* Wake up waiter. */
346 sema_up (&c->completion_wait);
349 printk ("%s: unexpected interrupt\n", c->name);
361 for (channel = 0; channel < CHANNEL_CNT; channel++)
363 struct channel *c = &channels[channel];
366 /* Initialize channel. */
367 snprintf (c->name, sizeof c->name, "ide%d", channel);
381 lock_init (&c->lock, c->name);
382 c->expecting_interrupt = false;
383 sema_init (&c->completion_wait, 0, c->name);
385 /* Initialize devices. */
386 for (device = 0; device < 2; device++)
388 struct disk *d = &c->dev[device];
389 snprintf (d->name, sizeof d->name, "%s:%d", c->name, device);
397 /* Register interrupt handler. */
398 intr_register (c->irq, 0, IF_OFF, interrupt_handler, c->name);
400 /* Reset hardware. */
403 /* Distinguish ATA hard disks from other devices. */
404 if (check_device_type (&c->dev[0]))
405 check_device_type (&c->dev[1]);
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]);
419 ASSERT (idx >= 0 && idx < 4);
420 d = &channels[idx / 2].dev[idx % 2];
421 return d->is_ata ? d : NULL;
425 disk_size (struct disk *d)
433 select_sector (struct disk *d, disk_sector_no sec_no)
435 struct channel *c = d->channel;
437 ASSERT (sec_no < d->capacity);
438 ASSERT (sec_no < (1UL << 28));
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));
450 disk_read (struct disk *d, disk_sector_no sec_no, void *buffer)
453 ASSERT (buffer != NULL);
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);
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);
466 disk_write (struct disk *d, disk_sector_no sec_no, const void *buffer)
469 ASSERT (buffer != NULL);
471 lock_acquire (&d->channel->lock);
472 select_sector (d, sec_no);
473 issue_command (d, CMD_WRITE_SECTOR_RETRY);
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);