X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=blobdiff_plain;f=src%2Fdevices%2Fdisk.c;h=14fc63158be840c550d7eb7a9d42d6ecb23b0c77;hp=5867caa19c2d599fa76d3f3bb4d217c67da596e5;hb=bb940d21474958a1d8ee2abffdcb6bac27918398;hpb=62cc6ff58f8b07dea772f8acfdfd9600f9c71ff4 diff --git a/src/devices/disk.c b/src/devices/disk.c index 5867caa..14fc631 100644 --- a/src/devices/disk.c +++ b/src/devices/disk.c @@ -8,6 +8,9 @@ #include "threads/interrupt.h" #include "threads/synch.h" +/* 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. */ #define reg_data(CHANNEL) ((CHANNEL)->reg_base + 0) /* Data. */ #define reg_error(CHANNEL) ((CHANNEL)->reg_base + 1) /* Error. */ @@ -27,6 +30,7 @@ /* Alternate Status Register bits. */ #define STA_BSY 0x80 /* Busy. */ +#define STA_DRDY 0x40 /* Device Ready. */ #define STA_DRQ 0x08 /* Data Request. */ /* Control Register bits. */ @@ -52,7 +56,10 @@ struct disk int dev_no; /* Device 0 or 1 for master or slave. */ bool is_ata; /* 1=This device is an ATA disk. */ - disk_sector_t capacity; /* Capacity in sectors (if is_ata is true). */ + disk_sector_t capacity; /* Capacity in sectors (if is_ata). */ + + long long read_cnt; /* Number of sectors read. */ + long long write_cnt; /* Number of sectors written. */ }; /* An ATA channel (aka controller). @@ -103,7 +110,7 @@ disk_init (void) int dev_no; /* Initialize channel. */ - snprintf (c->name, sizeof c->name, "hd%zd", chan_no); + snprintf (c->name, sizeof c->name, "hd%zu", chan_no); switch (chan_no) { case 0: @@ -117,9 +124,9 @@ disk_init (void) default: NOT_REACHED (); } - lock_init (&c->lock, c->name); + lock_init (&c->lock); c->expecting_interrupt = false; - sema_init (&c->completion_wait, 0, c->name); + sema_init (&c->completion_wait, 0); /* Initialize devices. */ for (dev_no = 0; dev_no < 2; dev_no++) @@ -131,10 +138,12 @@ disk_init (void) d->is_ata = false; d->capacity = 0; + + d->read_cnt = d->write_cnt = 0; } /* Register interrupt handler. */ - intr_register (c->irq, 0, INTR_OFF, interrupt_handler, c->name); + intr_register_ext (c->irq, interrupt_handler, c->name); /* Reset hardware. */ reset_channel (c); @@ -150,8 +159,35 @@ disk_init (void) } } +/* Prints disk statistics. */ +void +disk_print_stats (void) +{ + int chan_no; + + for (chan_no = 0; chan_no < CHANNEL_CNT; chan_no++) + { + int dev_no; + + for (dev_no = 0; dev_no < 2; dev_no++) + { + struct disk *d = disk_get (chan_no, dev_no); + if (d != NULL && d->is_ata) + printf ("%s: %lld reads, %lld writes\n", + d->name, d->read_cnt, d->write_cnt); + } + } +} + /* Returns the disk numbered DEV_NO--either 0 or 1 for master or - slave, respectively--within the channel numbered CHAN_NO. */ + slave, respectively--within the channel numbered CHAN_NO. + + Pintos uses disks this way: + 0:0 - boot loader, command line args, and operating system kernel + 0:1 - file system + 1:0 - scratch + 1:1 - swap +*/ struct disk * disk_get (int chan_no, int dev_no) { @@ -177,7 +213,9 @@ disk_size (struct disk *d) } /* Reads sector SEC_NO from disk D into BUFFER, which must have - room for DISK_SECTOR_SIZE bytes. */ + room for DISK_SECTOR_SIZE bytes. + Internally synchronizes accesses to disks, so external + per-disk locking is unneeded. */ void disk_read (struct disk *d, disk_sector_t sec_no, void *buffer) { @@ -194,12 +232,15 @@ disk_read (struct disk *d, disk_sector_t sec_no, void *buffer) if (!wait_while_busy (d)) PANIC ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no); input_sector (c, buffer); + d->read_cnt++; lock_release (&c->lock); } /* Write sector SEC_NO to disk D from BUFFER, which must contain DISK_SECTOR_SIZE bytes. Returns after the disk has - acknowledged receiving the data. */ + acknowledged receiving the data. + Internally synchronizes accesses to disks, so external + per-disk locking is unneeded. */ void disk_write (struct disk *d, disk_sector_t sec_no, const void *buffer) { @@ -216,6 +257,7 @@ disk_write (struct disk *d, disk_sector_t sec_no, const void *buffer) PANIC ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no); output_sector (c, buffer); sema_down (&c->completion_wait); + d->write_cnt++; lock_release (&c->lock); } @@ -255,12 +297,12 @@ reset_channel (struct channel *c) /* Issue soft reset sequence, which selects device 0 as a side effect. Also enable interrupts. */ outb (reg_ctl (c), 0); - timer_sleep (timer_us2ticks (10)); + timer_usleep (10); outb (reg_ctl (c), CTL_SRST); - timer_sleep (timer_us2ticks (10)); + timer_usleep (10); outb (reg_ctl (c), 0); - timer_sleep (timer_ms2ticks (150)); + timer_msleep (150); /* Wait for device 0 to clear BSY. */ if (present[0]) @@ -279,7 +321,7 @@ reset_channel (struct channel *c) { if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1) break; - timer_sleep (timer_ms2ticks (10)); + timer_msleep (10); } wait_while_busy (&c->devices[1]); } @@ -294,15 +336,18 @@ static bool check_device_type (struct disk *d) { struct channel *c = d->channel; - uint8_t error, lbam, lbah; + uint8_t error, lbam, lbah, status; select_device (d); error = inb (reg_error (c)); lbam = inb (reg_lbam (c)); lbah = inb (reg_lbah (c)); + status = inb (reg_status (c)); - if (error != 1 && (error != 0x81 || d->dev_no == 1)) + if ((error != 1 && (error != 0x81 || d->dev_no == 1)) + || (status & STA_DRDY) == 0 + || (status & STA_BSY) != 0) { d->is_ata = false; return error != 0x81; @@ -445,7 +490,7 @@ wait_until_idle (const struct disk *d) { if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0) return; - timer_sleep (timer_us2ticks (10)); + timer_usleep (10); } printf ("%s: idle timeout\n", d->name); @@ -471,7 +516,7 @@ wait_while_busy (const struct disk *d) printf ("ok\n"); return (inb (reg_alt_status (c)) & STA_DRQ) != 0; } - timer_sleep (timer_ms2ticks (10)); + timer_msleep (10); } printf ("failed\n"); @@ -488,7 +533,7 @@ select_device (const struct disk *d) dev |= DEV_DEV; outb (reg_device (c), dev); inb (reg_alt_status (c)); - timer_sleep (timer_ns2ticks (400)); + timer_nsleep (400); } /* Select disk D in its channel, as select_device(), but wait for