CS318 - Pintos
Pintos source browser for JHU CS318 course
Data Structures | Macros | Functions | Variables
ide.c File Reference
#include "devices/ide.h"
#include <ctype.h>
#include <debug.h>
#include <stdbool.h>
#include <stdio.h>
#include "devices/block.h"
#include "devices/partition.h"
#include "devices/timer.h"
#include "threads/io.h"
#include "threads/interrupt.h"
#include "threads/synch.h"
Include dependency graph for ide.c:

Go to the source code of this file.

Data Structures

struct  ata_disk
 An ATA device. More...
 
struct  channel
 An ATA channel (aka controller). More...
 

Macros

#define reg_data(CHANNEL)   ((CHANNEL)->reg_base + 0)
 The code in this file is an interface to an ATA (IDE) controller. More...
 
#define reg_error(CHANNEL)   ((CHANNEL)->reg_base + 1)
 Error. More...
 
#define reg_nsect(CHANNEL)   ((CHANNEL)->reg_base + 2)
 Sector Count. More...
 
#define reg_lbal(CHANNEL)   ((CHANNEL)->reg_base + 3)
 LBA 0:7. More...
 
#define reg_lbam(CHANNEL)   ((CHANNEL)->reg_base + 4)
 LBA 15:8. More...
 
#define reg_lbah(CHANNEL)   ((CHANNEL)->reg_base + 5)
 LBA 23:16. More...
 
#define reg_device(CHANNEL)   ((CHANNEL)->reg_base + 6)
 Device/LBA 27:24. More...
 
#define reg_status(CHANNEL)   ((CHANNEL)->reg_base + 7)
 Status (r/o). More...
 
#define reg_command(CHANNEL)   reg_status (CHANNEL)
 Command (w/o). More...
 
#define reg_ctl(CHANNEL)   ((CHANNEL)->reg_base + 0x206)
 ATA control block port addresses. More...
 
#define reg_alt_status(CHANNEL)   reg_ctl (CHANNEL)
 Alt Status (r/o). More...
 
#define STA_BSY   0x80
 Alternate Status Register bits. More...
 
#define STA_DRDY   0x40
 Device Ready. More...
 
#define STA_DRQ   0x08
 Data Request. More...
 
#define CTL_SRST   0x04
 Control Register bits. More...
 
#define DEV_MBS   0xa0
 Device Register bits. More...
 
#define DEV_LBA   0x40
 Linear based addressing. More...
 
#define DEV_DEV   0x10
 Select device: 0=master, 1=slave. More...
 
#define CMD_IDENTIFY_DEVICE   0xec
 Commands. More...
 
#define CMD_READ_SECTOR_RETRY   0x20
 READ SECTOR with retries. More...
 
#define CMD_WRITE_SECTOR_RETRY   0x30
 WRITE SECTOR with retries. More...
 
#define CHANNEL_CNT   2
 We support the two "legacy" ATA channels found in a standard PC. More...
 

Functions

static void reset_channel (struct channel *c)
 Resets an ATA channel and waits for any devices present on it to finish the reset. More...
 
static bool check_device_type (struct ata_disk *d)
 Checks whether device D is an ATA disk and sets D's is_ata member appropriately. More...
 
static void identify_ata_device (struct ata_disk *d)
 Sends an IDENTIFY DEVICE command to disk D and reads the response. More...
 
static void select_sector (struct ata_disk *d, block_sector_t sec_no)
 Selects device D, waiting for it to become ready, and then writes SEC_NO to the disk's sector selection registers. More...
 
static void issue_pio_command (struct channel *c, uint8_t command)
 Writes COMMAND to channel C and prepares for receiving a completion interrupt. More...
 
static void input_sector (struct channel *c, void *sector)
 Reads a sector from channel C's data register in PIO mode into SECTOR, which must have room for BLOCK_SECTOR_SIZE bytes. More...
 
static void output_sector (struct channel *c, const void *sector)
 Writes SECTOR to channel C's data register in PIO mode. More...
 
static void wait_until_idle (const struct ata_disk *d)
 Low-level ATA primitives. More...
 
static bool wait_while_busy (const struct ata_disk *d)
 Wait up to 30 seconds for disk D to clear BSY, and then return the status of the DRQ bit. More...
 
static void select_device (const struct ata_disk *d)
 Program D's channel so that D is now the selected disk. More...
 
static void select_device_wait (const struct ata_disk *d)
 Select disk D in its channel, as select_device(), but wait for the channel to become idle before and after. More...
 
static void interrupt_handler (struct intr_frame *f)
 ATA interrupt handler. More...
 
void ide_init (void)
 Initialize the disk subsystem and detect disks. More...
 
static char * descramble_ata_string (char *, int size)
 Disk detection and identification. More...
 
static void ide_read (void *d_, block_sector_t sec_no, void *buffer)
 Reads sector SEC_NO from disk D into BUFFER, which must have room for BLOCK_SECTOR_SIZE bytes. More...
 
static void ide_write (void *d_, block_sector_t sec_no, const void *buffer)
 Write sector SEC_NO to disk D from BUFFER, which must contain BLOCK_SECTOR_SIZE bytes. More...
 

Variables

static struct channel channels [CHANNEL_CNT]
 
static struct block_operations ide_operations
 

Macro Definition Documentation

◆ CHANNEL_CNT

#define CHANNEL_CNT   2

We support the two "legacy" ATA channels found in a standard PC.

Definition at line 79 of file ide.c.

◆ CMD_IDENTIFY_DEVICE

#define CMD_IDENTIFY_DEVICE   0xec

Commands.

Many more are defined but this is the small subset that we use. IDENTIFY DEVICE.

Definition at line 49 of file ide.c.

◆ CMD_READ_SECTOR_RETRY

#define CMD_READ_SECTOR_RETRY   0x20

READ SECTOR with retries.

Definition at line 50 of file ide.c.

◆ CMD_WRITE_SECTOR_RETRY

#define CMD_WRITE_SECTOR_RETRY   0x30

WRITE SECTOR with retries.

Definition at line 51 of file ide.c.

◆ CTL_SRST

#define CTL_SRST   0x04

Control Register bits.

Software Reset.

Definition at line 39 of file ide.c.

◆ DEV_DEV

#define DEV_DEV   0x10

Select device: 0=master, 1=slave.

Definition at line 44 of file ide.c.

◆ DEV_LBA

#define DEV_LBA   0x40

Linear based addressing.

Definition at line 43 of file ide.c.

◆ DEV_MBS

#define DEV_MBS   0xa0

Device Register bits.

Must be set.

Definition at line 42 of file ide.c.

◆ reg_alt_status

#define reg_alt_status (   CHANNEL)    reg_ctl (CHANNEL)

Alt Status (r/o).

Definition at line 31 of file ide.c.

◆ reg_command

#define reg_command (   CHANNEL)    reg_status (CHANNEL)

Command (w/o).

Definition at line 25 of file ide.c.

◆ reg_ctl

#define reg_ctl (   CHANNEL)    ((CHANNEL)->reg_base + 0x206)

ATA control block port addresses.

(If we supported non-legacy ATA controllers this would not be flexible enough, but it's fine for what we do.) Control (w/o).

Definition at line 30 of file ide.c.

◆ reg_data

#define reg_data (   CHANNEL)    ((CHANNEL)->reg_base + 0)

The code in this file is an interface to an ATA (IDE) controller.

It attempts to comply to [ATA-3]. ATA command block port addresses. Data.

Definition at line 17 of file ide.c.

◆ reg_device

#define reg_device (   CHANNEL)    ((CHANNEL)->reg_base + 6)

Device/LBA 27:24.

Definition at line 23 of file ide.c.

◆ reg_error

#define reg_error (   CHANNEL)    ((CHANNEL)->reg_base + 1)

Error.

Definition at line 18 of file ide.c.

◆ reg_lbah

#define reg_lbah (   CHANNEL)    ((CHANNEL)->reg_base + 5)

LBA 23:16.

Definition at line 22 of file ide.c.

◆ reg_lbal

#define reg_lbal (   CHANNEL)    ((CHANNEL)->reg_base + 3)

LBA 0:7.

Definition at line 20 of file ide.c.

◆ reg_lbam

#define reg_lbam (   CHANNEL)    ((CHANNEL)->reg_base + 4)

LBA 15:8.

Definition at line 21 of file ide.c.

◆ reg_nsect

#define reg_nsect (   CHANNEL)    ((CHANNEL)->reg_base + 2)

Sector Count.

Definition at line 19 of file ide.c.

◆ reg_status

#define reg_status (   CHANNEL)    ((CHANNEL)->reg_base + 7)

Status (r/o).

Definition at line 24 of file ide.c.

◆ STA_BSY

#define STA_BSY   0x80

Alternate Status Register bits.

Busy.

Definition at line 34 of file ide.c.

◆ STA_DRDY

#define STA_DRDY   0x40

Device Ready.

Definition at line 35 of file ide.c.

◆ STA_DRQ

#define STA_DRQ   0x08

Data Request.

Definition at line 36 of file ide.c.

Function Documentation

◆ check_device_type()

static bool check_device_type ( struct ata_disk d)
static

Checks whether device D is an ATA disk and sets D's is_ata member appropriately.

If D is device 0 (master), returns true if it's possible that a slave (device 1) exists on this channel. If D is device 1 (slave), the return value is not meaningful.

Definition at line 230 of file ide.c.

References ata_disk::channel, ata_disk::dev_no, inb(), ata_disk::is_ata, reg_error, reg_lbah, reg_lbam, reg_status, select_device(), STA_BSY, and STA_DRDY.

Referenced by ide_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ descramble_ata_string()

static char * descramble_ata_string ( char *  string,
int  size 
)
static

Disk detection and identification.

Translates STRING, which consists of SIZE bytes in a funky format, into a null-terminated string in-place.

Drops trailing whitespace and null bytes. Returns STRING.

Definition at line 316 of file ide.c.

References isspace(), and block::size.

Referenced by identify_ata_device().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ide_init()

void ide_init ( void  )

◆ ide_read()

static void ide_read ( void *  d_,
block_sector_t  sec_no,
void *  buffer 
)
static

Reads sector SEC_NO from disk D into BUFFER, which must have room for BLOCK_SECTOR_SIZE bytes.

Internally synchronizes accesses to disks, so external per-disk locking is unneeded.

Definition at line 345 of file ide.c.

References buffer, ata_disk::channel, CMD_READ_SECTOR_RETRY, channel::completion_wait, input_sector(), issue_pio_command(), channel::lock, lock_acquire(), lock_release(), ata_disk::name, PANIC, PRDSNu, select_sector(), sema_down(), and wait_while_busy().

Here is the call graph for this function:

◆ ide_write()

static void ide_write ( void *  d_,
block_sector_t  sec_no,
const void *  buffer 
)
static

Write sector SEC_NO to disk D from BUFFER, which must contain BLOCK_SECTOR_SIZE bytes.

Returns after the disk has acknowledged receiving the data. Internally synchronizes accesses to disks, so external per-disk locking is unneeded.

Definition at line 365 of file ide.c.

References buffer, ata_disk::channel, CMD_WRITE_SECTOR_RETRY, channel::completion_wait, issue_pio_command(), channel::lock, lock_acquire(), lock_release(), ata_disk::name, output_sector(), PANIC, PRDSNu, select_sector(), sema_down(), and wait_while_busy().

Here is the call graph for this function:

◆ identify_ata_device()

static void identify_ata_device ( struct ata_disk d)
static

Sends an IDENTIFY DEVICE command to disk D and reads the response.

Registers the disk with the block device layer.

Definition at line 260 of file ide.c.

References ASSERT, BLOCK_RAW, block_register(), BLOCK_SECTOR_SIZE, ata_disk::channel, CMD_IDENTIFY_DEVICE, channel::completion_wait, descramble_ata_string(), ide_operations, input_sector(), ata_disk::is_ata, issue_pio_command(), ata_disk::name, partition_scan(), print_human_readable_size(), printf(), select_device_wait(), sema_down(), snprintf(), and wait_while_busy().

Referenced by ide_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ input_sector()

static void input_sector ( struct channel c,
void *  sector 
)
static

Reads a sector from channel C's data register in PIO mode into SECTOR, which must have room for BLOCK_SECTOR_SIZE bytes.

Definition at line 420 of file ide.c.

References BLOCK_SECTOR_SIZE, insw(), and reg_data.

Referenced by ide_read(), and identify_ata_device().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ interrupt_handler()

static void interrupt_handler ( struct intr_frame f)
static

ATA interrupt handler.

< Acknowledge interrupt.

< Wake up waiter.

Definition at line 507 of file ide.c.

References CHANNEL_CNT, channels, channel::completion_wait, channel::expecting_interrupt, inb(), channel::irq, channel::name, NOT_REACHED, printf(), reg_status, sema_up(), and intr_frame::vec_no.

Referenced by ide_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ issue_pio_command()

static void issue_pio_command ( struct channel c,
uint8_t  command 
)
static

Writes COMMAND to channel C and prepares for receiving a completion interrupt.

Definition at line 407 of file ide.c.

References ASSERT, channel::expecting_interrupt, intr_get_level(), INTR_ON, outb(), and reg_command.

Referenced by ide_read(), ide_write(), and identify_ata_device().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ output_sector()

static void output_sector ( struct channel c,
const void *  sector 
)
static

Writes SECTOR to channel C's data register in PIO mode.

SECTOR must contain BLOCK_SECTOR_SIZE bytes.

Definition at line 428 of file ide.c.

References BLOCK_SECTOR_SIZE, outsw(), and reg_data.

Referenced by ide_write().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset_channel()

static void reset_channel ( struct channel c)
static

Resets an ATA channel and waits for any devices present on it to finish the reset.

Definition at line 165 of file ide.c.

References CTL_SRST, ata_disk::dev_no, channel::devices, inb(), outb(), reg_ctl, reg_lbal, reg_nsect, select_device(), timer_msleep(), timer_usleep(), and wait_while_busy().

Referenced by ide_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_device()

static void select_device ( const struct ata_disk d)
static

Program D's channel so that D is now the selected disk.

Definition at line 484 of file ide.c.

References ata_disk::channel, DEV_DEV, DEV_MBS, ata_disk::dev_no, inb(), outb(), reg_alt_status, reg_device, and timer_nsleep().

Referenced by check_device_type(), reset_channel(), and select_device_wait().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_device_wait()

static void select_device_wait ( const struct ata_disk d)
static

Select disk D in its channel, as select_device(), but wait for the channel to become idle before and after.

Definition at line 498 of file ide.c.

References select_device(), and wait_until_idle().

Referenced by identify_ata_device(), and select_sector().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_sector()

static void select_sector ( struct ata_disk d,
block_sector_t  sec_no 
)
static

Selects device D, waiting for it to become ready, and then writes SEC_NO to the disk's sector selection registers.

(We use LBA mode.)

Definition at line 389 of file ide.c.

References ASSERT, ata_disk::channel, DEV_DEV, DEV_LBA, DEV_MBS, ata_disk::dev_no, outb(), reg_device, reg_lbah, reg_lbal, reg_lbam, reg_nsect, and select_device_wait().

Referenced by ide_read(), and ide_write().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ wait_until_idle()

static void wait_until_idle ( const struct ata_disk d)
static

Low-level ATA primitives.

Wait up to 10 seconds for the controller to become idle, that is, for the BSY and DRQ bits to clear in the status register.

As a side effect, reading the status register clears any pending interrupt.

Definition at line 441 of file ide.c.

References ata_disk::channel, inb(), ata_disk::name, printf(), reg_status, STA_BSY, STA_DRQ, and timer_usleep().

Referenced by select_device_wait().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ wait_while_busy()

static bool wait_while_busy ( const struct ata_disk d)
static

Wait up to 30 seconds for disk D to clear BSY, and then return the status of the DRQ bit.

The ATA standards say that a disk may take as long as that to complete its reset.

Definition at line 460 of file ide.c.

References ata_disk::channel, inb(), ata_disk::name, printf(), reg_alt_status, STA_BSY, STA_DRQ, and timer_msleep().

Referenced by ide_read(), ide_write(), identify_ata_device(), and reset_channel().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ channels

struct channel channels[CHANNEL_CNT]
static

Definition at line 80 of file ide.c.

Referenced by ide_init(), and interrupt_handler().

◆ ide_operations

static struct block_operations ide_operations
static
Initial value:

Definition at line 82 of file ide.c.

Referenced by identify_ata_device().

ide_write
static void ide_write(void *d_, block_sector_t sec_no, const void *buffer)
Write sector SEC_NO to disk D from BUFFER, which must contain BLOCK_SECTOR_SIZE bytes.
Definition: ide.c:365
ide_read
static void ide_read(void *d_, block_sector_t sec_no, void *buffer)
Reads sector SEC_NO from disk D into BUFFER, which must have room for BLOCK_SECTOR_SIZE bytes.
Definition: ide.c:345