17#define reg_data(CHANNEL) ((CHANNEL)->reg_base + 0)
18#define reg_error(CHANNEL) ((CHANNEL)->reg_base + 1)
19#define reg_nsect(CHANNEL) ((CHANNEL)->reg_base + 2)
20#define reg_lbal(CHANNEL) ((CHANNEL)->reg_base + 3)
21#define reg_lbam(CHANNEL) ((CHANNEL)->reg_base + 4)
22#define reg_lbah(CHANNEL) ((CHANNEL)->reg_base + 5)
23#define reg_device(CHANNEL) ((CHANNEL)->reg_base + 6)
24#define reg_status(CHANNEL) ((CHANNEL)->reg_base + 7)
25#define reg_command(CHANNEL) reg_status (CHANNEL)
30#define reg_ctl(CHANNEL) ((CHANNEL)->reg_base + 0x206)
31#define reg_alt_status(CHANNEL) reg_ctl (CHANNEL)
49#define CMD_IDENTIFY_DEVICE 0xec
50#define CMD_READ_SECTOR_RETRY 0x20
51#define CMD_WRITE_SECTOR_RETRY 0x30
106 for (chan_no = 0; chan_no <
CHANNEL_CNT; chan_no++)
131 for (dev_no = 0; dev_no < 2; dev_no++)
135 "hd%c",
'a' + chan_no * 2 +
dev_no);
214 for (i = 0; i < 3000; i++)
233 uint8_t error, lbam, lbah, status;
242 if ((error != 1 && (error != 0x81 || d->
dev_no == 1))
247 return error != 0x81;
251 d->
is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
265 char *model, *serial;
266 char extra_info[128];
286 capacity = *(
uint32_t *) &
id[60 * 2];
289 snprintf (extra_info,
sizeof extra_info,
290 "model \"%s\", serial \"%s\"", model, serial);
301 printf (
"disk for safety\n");
321 for (i = 0; i + 1 <
size; i += 2)
323 char tmp =
string[i];
324 string[i] =
string[i + 1];
331 int c =
string[
size - 1];
393 ASSERT (sec_no < (1UL << 28));
445 for (i = 0; i < 1000; i++)
465 for (i = 0; i < 3000; i++)
520 printf (
"%s: unexpected interrupt\n", c->
name);
struct block * block_register(const char *name, enum block_type type, const char *extra_info, block_sector_t size, const struct block_operations *ops, void *aux)
Registers a new block device with the given NAME.
uint32_t block_sector_t
Index of a block device sector.
#define BLOCK_SECTOR_SIZE
Size of a block device sector in bytes.
#define PRDSNu
Format specifier for printf(), e.g.
@ BLOCK_RAW
"Raw" device with unidentified contents.
static int isspace(int c)
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
#define NOT_REACHED()
lib/debug.h
#define PANIC(...)
Halts the OS, printing the source file name, line number, and function name, plus a user-specific mes...
static struct block_operations ide_operations
static void reset_channel(struct channel *)
Resets an ATA channel and waits for any devices present on it to finish the reset.
#define reg_ctl(CHANNEL)
ATA control block port addresses.
#define reg_device(CHANNEL)
Device/LBA 27:24.
#define CTL_SRST
Control Register bits.
#define DEV_DEV
Select device: 0=master, 1=slave.
static bool wait_while_busy(const struct ata_disk *)
Wait up to 30 seconds for disk D to clear BSY, and then return the status of the DRQ bit.
#define CMD_IDENTIFY_DEVICE
Commands.
#define DEV_LBA
Linear based addressing.
#define reg_data(CHANNEL)
The code in this file is an interface to an ATA (IDE) controller.
#define reg_lbal(CHANNEL)
LBA 0:7.
#define reg_nsect(CHANNEL)
Sector Count.
#define reg_lbah(CHANNEL)
LBA 23:16.
static void select_device_wait(const struct ata_disk *)
Select disk D in its channel, as select_device(), but wait for the channel to become idle before and ...
void ide_init(void)
Initialize the disk subsystem and detect disks.
static char * descramble_ata_string(char *, int size)
Disk detection and identification.
static void select_device(const struct ata_disk *)
Program D's channel so that D is now the selected disk.
#define reg_status(CHANNEL)
Status (r/o).
static void output_sector(struct channel *, const void *)
Writes SECTOR to channel C's data register in PIO mode.
#define reg_alt_status(CHANNEL)
Alt Status (r/o).
#define STA_DRDY
Device Ready.
#define STA_DRQ
Data Request.
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.
static void interrupt_handler(struct intr_frame *)
ATA interrupt handler.
#define DEV_MBS
Device Register bits.
#define STA_BSY
Alternate Status Register bits.
#define reg_error(CHANNEL)
Error.
#define CMD_WRITE_SECTOR_RETRY
WRITE SECTOR with retries.
#define reg_command(CHANNEL)
Command (w/o).
#define CMD_READ_SECTOR_RETRY
READ SECTOR with retries.
static void wait_until_idle(const struct ata_disk *)
Low-level ATA primitives.
static void issue_pio_command(struct channel *, uint8_t command)
Writes COMMAND to channel C and prepares for receiving a completion interrupt.
static void input_sector(struct channel *, void *)
Reads a sector from channel C's data register in PIO mode into SECTOR, which must have room for BLOCK...
static void select_sector(struct ata_disk *, block_sector_t)
Selects device D, waiting for it to become ready, and then writes SEC_NO to the disk's sector selecti...
static struct channel channels[CHANNEL_CNT]
#define CHANNEL_CNT
We support the two "legacy" ATA channels found in a standard PC.
#define reg_lbam(CHANNEL)
LBA 15:8.
static bool check_device_type(struct ata_disk *)
Checks whether device D is an ATA disk and sets D's is_ata member appropriately.
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.
static void identify_ata_device(struct ata_disk *)
Sends an IDENTIFY DEVICE command to disk D and reads the response.
void intr_register_ext(uint8_t vec_no, intr_handler_func *handler, const char *name)
Registers external interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes.
enum intr_level intr_get_level(void)
Returns the current interrupt status.
@ INTR_ON
Interrupts enabled.
static uint8_t inb(uint16_t port)
Reads and returns a byte from PORT.
static void outsw(uint16_t port, const void *addr, size_t cnt)
Writes to PORT each 16-bit unit (halfword) of data in the CNT-halfword buffer starting at ADDR.
static void insw(uint16_t port, void *addr, size_t cnt)
Reads CNT 16-bit (halfword) units from PORT, one after another, and stores them into the buffer start...
static void outb(uint16_t port, uint8_t data)
Writes byte DATA to PORT.
void print_human_readable_size(uint64_t size)
Prints SIZE, which represents a number of bytes, in a human-readable format, e.g.
int snprintf(char *buffer, size_t buf_size, const char *format,...)
Like printf(), except that output is stored into BUFFER, which must have space for BUF_SIZE character...
int printf(const char *format,...)
Writes formatted output to the console.
void partition_scan(struct block *block)
Scans BLOCK for partitions of interest to Pintos.
unsigned short int uint16_t
bool is_ata
Is device an ATA disk?
int dev_no
Device 0 or 1 for master or slave.
struct channel * channel
Channel that disk is attached to.
Lower-level interface to block device drivers.
block_sector_t size
Size in sectors.
An ATA channel (aka controller).
struct ata_disk devices[2]
The devices on this channel.
bool expecting_interrupt
True if an interrupt is expected, false if any interrupt would be spurious.
struct semaphore completion_wait
Up'd by interrupt handler.
uint16_t reg_base
Base I/O port.
uint8_t irq
Interrupt in use.
struct lock lock
Must acquire to access the controller.
uint16_t uint16_t uint16_t uint16_t uint32_t vec_no
Saved DS segment register.
void lock_release(struct lock *lock)
Releases LOCK, which must be owned by the current thread.
void sema_init(struct semaphore *sema, unsigned value)
This file is derived from source code for the Nachos instructional operating system.
void sema_up(struct semaphore *sema)
Up or "V" operation on a semaphore.
void lock_init(struct lock *lock)
Initializes LOCK.
void lock_acquire(struct lock *lock)
Acquires LOCK, sleeping until it becomes available if necessary.
void sema_down(struct semaphore *sema)
Down or "P" operation on a semaphore.
void timer_msleep(int64_t ms)
Sleeps for approximately MS milliseconds.
void timer_nsleep(int64_t ns)
Sleeps for approximately NS nanoseconds.
void timer_usleep(int64_t us)
Sleeps for approximately US microseconds.