Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/ata/ata.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "drivers/ata/ata.h"
0019 #include "arch/i386.h"
0020 #include "arch/i386-div64.h"
0021 #include "util/printf.h"
0022 #include "smp/smp.h"
0023 #include "smp/apic.h"
0024 #include "sched/sched.h"
0025 #include "sched/vcpu.h"
0026 #include "kernel.h"
0027 
0028 //#define DEBUG_ATA
0029 #ifdef DEBUG_ATA
0030 #define DLOG(fmt,...) DLOG_PREFIX("ata",fmt,##__VA_ARGS__)
0031 #else
0032 #define DLOG(fmt,...) ;
0033 #endif
0034 
0035 
0036 /**************************************************************************
0037  *  IDENTIFY command                                                      *
0038  *                                                                        *
0039  * To use the IDENTIFY command, select a target drive by sending 0xA0 for *
0040  * the master drive, or 0xB0 for the slave, to the "drive select" IO      *
0041  * port. On the Primary bus, this would be port 0x1F6. A 400ns delay is a *
0042  * good idea. Then send the IDENTIFY command (0xEC) to the Command IO     *
0043  * port (0x1F7). Then read the Status port (0x1F7) again. If the value    *
0044  * read is 0, the drive does not exist. For any other value: poll the     *
0045  * Status port (0x1F7) until bit 7 (BSY, value = 0x80) clears, and bit 3  *
0046  * (DRQ, value = 8) sets -- or until bit 0 (ERR, value = 1) sets. At that *
0047  * point, if ERR is clear, the data is ready to read from the Data port   *
0048  * (0x1F0). Read 256 words, and store them.  "Command Aborted"            *
0049  *                                                                        *
0050  * ATAPI or SATA devices will respond to an ATA IDENTIFY command by       *
0051  * immediately reporting an error in the Status Register, rather than     *
0052  * setting BSY, then DRQ, then sending 256 words of PIO data. These       *
0053  * devices will also write specific values to the IO ports, that can be   *
0054  * read. Seeing ATAPI specific values on those ports after this sort of   *
0055  * "abort" is definitive proof that the device is ATAPI -- on the Primary *
0056  * bus, IO port 0x1F4 will read as 0x14, and IO port 0x1F5 will read as   *
0057  * 0xEB. If a normal ATA drive should ever happen to abort an IDENTIFY    *
0058  * command, the values in those two ports will be 0. A SATA device will   *
0059  * report 0x3c, and 0xc3 instead. See below for a code example.           *
0060  *                                                                        *
0061  * Make sure to note that this means it is important to check the ERR bit *
0062  * (bit 0, value = 1) in the Regular or Alternate Status register, before *
0063  * trying to read the 256 words of PIO data.  Interesting information     *
0064  * returned by IDENTIFY                                                   *
0065  *                                                                        *
0066  *     * Word 0: is useful if the device is not a hard disk.              *
0067  *                                                                        *
0068  *     * Word 83: Bit 10 is set if the drive supports LBA48 mode.         *
0069  *                                                                        *
0070  *     * Word 88: The bits in the low byte tell you the supported UDMA    *
0071  *     * modes, the upper byte tells you which UDMA mode is active. If    *
0072  *     * the active mode is not the highest supported mode, you may want  *
0073  *     * to figure out why.                                               *
0074  *                                                                        *
0075  *     * Word 93 from a master drive on the bus: Bit 12 is supposed to be *
0076  *     * set if the drive detects an 80 pin cable.                        *
0077  *                                                                        *
0078  *     * Words 60 & 61 taken as a uint32 contain the total number of 28    *
0079  *     * bit LBA addressable sectors on the drive. (If non-zero, the      *
0080  *     * drive supports LBA28.)                                           *
0081  *                                                                        *
0082  *     * Words 100 through 103 taken as a uint64 contain the total number  *
0083  *     * of 48 bit addressable sectors on the drive. (Probably also proof *
0084  *     * that LBA48 is supported.)                                        *
0085  **************************************************************************/
0086 
0087 ata_info pata_drives[4];
0088 /* ata_current_task has exclusive access to ATA.  If an ATA IRQ comes
0089  * in, we assume that ata_current_task is waiting on it and needs to
0090  * be woken. */
0091 static uint16 ata_current_task = 0;
0092 /* waitqueue of tasks that want to use ATA. */
0093 static uint16 ata_waitqueue = 0;
0094 
0095 /* technically I think there could be separate queues for each bus,
0096  * but, whatever. */
0097 
0098 /* Kernel lock should be held while using ATA */
0099 
0100 /* relinquish CPU until we get exclusive access to the ATA subsystem */
0101 static void
0102 ata_grab (void)
0103 {
0104   DLOG ("ata_grab() ata_current_task=%x ata_waitqueue=%x tr=%x",
0105         ata_current_task, ata_waitqueue, str ());
0106   while (ata_current_task) {
0107     queue_append (&ata_waitqueue, str ());
0108     schedule ();
0109   }
0110   ata_current_task = str ();
0111 }
0112 
0113 static void
0114 ata_release (void)
0115 {
0116   DLOG ("ata_release() ata_current_task=%x ata_waitqueue=%x tr=%x",
0117         ata_current_task, ata_waitqueue, str ());
0118   wakeup_queue (&ata_waitqueue);
0119   ata_waitqueue = 0;
0120   ata_current_task = 0;
0121 }
0122 
0123 /* ATA specifies a 400ns delay after drive switching -- often
0124  * implemented as 4 Alternative Status queries. */
0125 #define ATA_SELECT_DELAY(bus) \
0126   {inb(ATA_DCR(bus));inb(ATA_DCR(bus));inb(ATA_DCR(bus));inb(ATA_DCR(bus));}
0127 
0128 /* Soft-reset the ATA bus. */
0129 void
0130 ata_sreset (uint32 bus)
0131 {
0132   outb (0x02, ATA_DCR (bus));
0133   outb (0x00, ATA_DCR (bus));
0134 }
0135 
0136 /* Tell the bus controller to select master or slave drive for
0137  * subsequent operations. */
0138 void
0139 ata_drive_select (uint32 bus, uint32 drive)
0140 {
0141   outb (drive, ATA_DRIVE_SELECT (bus));
0142   ATA_SELECT_DELAY (bus);
0143 }
0144 
0145 /* Use the ATA IDENTIFY command to find out what kind of drive is
0146  * attached to the given bus/slot. */
0147 uint32
0148 ata_identify (uint32 bus, uint32 drive)
0149 {
0150   uint8 status;
0151   uint16 buffer[256];
0152 
0153   ata_drive_select (bus, drive);
0154 
0155   outb (0xEC, ATA_COMMAND (bus));       /* Send IDENTIFY command */
0156 
0157   ATA_SELECT_DELAY (bus);
0158 
0159   status = inb (ATA_COMMAND (bus));
0160   if (status == 0) {
0161     logger_printf ("ATA bus %X drive %X does not exist\n", bus, drive);
0162     return ATA_TYPE_NONE;
0163   }
0164 
0165   if (status & 0x1) {
0166     /* Drive does not support IDENTIFY.  Probably a CD-ROM. */
0167     goto guess_identity;
0168   }
0169 
0170   /* Poll the Status port (0x1F7) until bit 7 (BSY, value = 0x80)
0171    * clears, and bit 3 (DRQ, value = 8) sets -- or until bit 0 (ERR,
0172    * value = 1) sets. */
0173 
0174   while ((status = inb (ATA_COMMAND (bus))) & 0x80)     /* BUSY */
0175     asm volatile ("pause");
0176 
0177   while (!((status = inb (ATA_COMMAND (bus))) & 0x8) && !(status & 0x1))
0178     asm volatile ("pause");
0179 
0180   if (status & 0x1) {
0181     logger_printf ("ATA bus %X drive %X caused error.\n", bus, drive);
0182     goto guess_identity;
0183   }
0184 
0185   /* Read 256 words */
0186   insw (ATA_DATA (bus), buffer, 256);
0187 
0188 #ifdef DEBUG_ATA
0189   {
0190     int i, j;
0191 
0192     DLOG ("IDENTIFY (bus: %X drive: %X) command output:", bus, drive);
0193     /* dump to com1 */
0194     for (i = 0; i < 32; i++) {
0195       for (j = 0; j < 8; j++) {
0196         com1_printf ("%.4X ", buffer[i * 32 + j]);
0197       }
0198       com1_printf ("\n");
0199     }
0200   }
0201 #endif
0202 
0203   if (buffer[83] & (1 << 10))
0204     logger_printf ("LBA48 mode supported.\n");
0205   logger_printf ("LBA48 addressable sectors: %.4X %.4X %.4X %.4X\n",
0206                  buffer[100], buffer[101], buffer[102], buffer[103]);
0207   return ATA_TYPE_PATA;
0208 
0209 guess_identity:{
0210     uint8 b1, b2;
0211 
0212     b1 = inb (ATA_ADDRESS2 (bus));
0213     b2 = inb (ATA_ADDRESS3 (bus));
0214 
0215     com1_printf ("ata_detect: %.2X %.2X\n", b1, b2);
0216 
0217     if (b1 == 0x14 && b2 == 0xEB) {
0218       logger_printf ("P-ATAPI detected\n");
0219       return ATA_TYPE_PATAPI;
0220     }
0221     if (b1 == 0x69 && b2 == 0x96) {
0222       logger_printf ("S-ATAPI detected\n");
0223       return ATA_TYPE_SATAPI;
0224     }
0225     if (b1 == 0x3C && b2 == 0xC3) {
0226       logger_printf ("SATA detected\n");
0227       return ATA_TYPE_SATA;
0228     }
0229     return ATA_TYPE_NONE;
0230   }
0231 }
0232 
0233 static void ata_poll_for_irq (uint32);
0234 
0235 /* Read a sector from the bus/drive using LBA into the given buffer
0236  * and return bytes read. */
0237 int
0238 ata_drive_read_sector (uint32 bus, uint32 drive, uint32 lba, uint8 * buffer)
0239 {
0240   uint8 status;
0241   int ret;
0242   ata_grab ();
0243   outb (drive | 0x40 /* LBA */  | ((lba >> 24) & 0x0F),
0244         ATA_DRIVE_SELECT (bus));
0245   ATA_SELECT_DELAY (bus);
0246   outb (0x1, ATA_SECTOR_COUNT (bus));
0247   outb ((uint8) lba, ATA_ADDRESS1 (bus));
0248   outb ((uint8) (lba >> 8), ATA_ADDRESS2 (bus));
0249   outb ((uint8) (lba >> 16), ATA_ADDRESS3 (bus));
0250   outb (0x20, ATA_COMMAND (bus));       /* READ SECTORS (28-bit LBA) */
0251 
0252   if (sched_enabled)
0253     schedule ();
0254   else
0255     ata_poll_for_irq (bus);
0256 
0257   while (!(status = inb (ATA_COMMAND (bus)) & 0x8) && !(status & 0x1))
0258     asm volatile ("pause");
0259   if (status & 0x1) {
0260     ret = -1;
0261     goto cleanup;
0262   }
0263   insw (ATA_DATA (bus), buffer, 256);
0264 
0265   ret = 512;
0266 
0267  cleanup:
0268   ata_release ();
0269   return ret;
0270 }
0271 
0272 /* Write a sector to the bus/drive using LBA from the given buffer
0273  * and return bytes written. */
0274 int
0275 ata_drive_write_sector (uint32 bus, uint32 drive, uint32 lba, uint8 * buffer)
0276 {
0277   uint8 status;
0278   int i, ret;
0279   outb (drive | 0x40 /* LBA */  | ((lba >> 24) & 0x0F),
0280         ATA_DRIVE_SELECT (bus));
0281   ATA_SELECT_DELAY (bus);
0282   outb (0x1, ATA_SECTOR_COUNT (bus));
0283   outb ((uint8) lba, ATA_ADDRESS1 (bus));
0284   outb ((uint8) (lba >> 8), ATA_ADDRESS2 (bus));
0285   outb ((uint8) (lba >> 16), ATA_ADDRESS3 (bus));
0286   outb (0x30, ATA_COMMAND (bus));       /* WRITE SECTORS (28-bit LBA) */
0287   while (!(status = inb (ATA_COMMAND (bus)) & 0x8) && !(status & 0x1))
0288     asm volatile ("pause");
0289   if (status & 0x1) {
0290     ret = -1;
0291     goto cleanup;
0292   }
0293 
0294   /* ``Do not use REP OUTSW to transfer data. There must be a tiny
0295    * delay between each OUTSW output word. A jmp $+2 size of
0296    * delay. Make sure to do a Cache Flush (ATA command 0xE7) after
0297    * each write command completes.'' */
0298 
0299   for (i = 0; i < 256; i++)
0300     outw (((uint16 *) buffer)[i], ATA_DATA (bus));
0301 
0302   outb (0xE7, ATA_COMMAND (bus));       /* FLUSH */
0303 
0304   ret = 512;
0305 
0306  cleanup:
0307   ata_release ();
0308   return ret;
0309 }
0310 
0311 /* Count number of times IRQs are triggered. */
0312 uint32 ata_primary_irq_count = 0, ata_secondary_irq_count = 0;
0313 uint32 ata_irq_count = 0;
0314 u64 irq_turnaround = 0, irq_response = 0, irq_start = 0, irq_resp_max = 0;
0315 u64 irq_resp_min = ~0LL;
0316 
0317 /* IRQ handler for both drive controllers. */
0318 static uint32
0319 ata_irq_handler (uint8 vec)
0320 {
0321   lock_kernel ();
0322   DLOG ("ata_irq_handler(%x) ata_current_task=%x", vec,
0323         ata_current_task);
0324   if (vec == ATA_VECTOR_PRIMARY)
0325     ata_primary_irq_count++;
0326   else
0327     ata_secondary_irq_count++;
0328 
0329   if (irq_start != 0)
0330     ata_irq_count++;
0331 
0332   u64 finish;
0333   RDTSC (finish);
0334   if (irq_start != 0) {
0335     irq_response += finish - irq_start;
0336     if (irq_resp_max < finish - irq_start)
0337       irq_resp_max = finish - irq_start;
0338     if (irq_resp_min > finish - irq_start)
0339       irq_resp_min = finish - irq_start;
0340   }
0341 
0342   /* Unblock the task waiting for the IRQ. */
0343   if (ata_current_task)
0344     wakeup (ata_current_task);
0345 
0346   unlock_kernel ();
0347   return 0;
0348 }
0349 
0350 /* Temporary handler for timer IRQ. */
0351 void
0352 ata_poll_for_irq_timer_handler (void)
0353 {
0354   send_eoi ();
0355   asm volatile ("leave");
0356   asm volatile ("iret");
0357 }
0358 
0359 /* Use this function if ATA IRQs are expected but scheduling is not
0360  * ready yet.  The original intention of this function was to disable
0361  * all but the disk IRQ and then wait for it to arrive.  This didn't
0362  * work out, so for the time being, it is just a hard-coded delay. */
0363 static void
0364 ata_poll_for_irq (uint32 bus)
0365 {
0366 #if 0
0367   uint32 count, *counter;
0368   idt_descriptor old_timer;
0369   /* Use this if scheduling is not enabled yet */
0370   counter =
0371     (bus ==
0372      ATA_BUS_PRIMARY ? &ata_primary_irq_count : &ata_secondary_irq_count);
0373   disable_idt ();
0374   get_idt_descriptor (0x20, &old_timer);
0375   set_idt_descriptor_by_addr (0x20, (void *) &ata_poll_for_irq_timer_handler,
0376                               0x3);
0377   enable_idt_entry (ATA_VECTOR (bus));
0378   count = *counter;
0379   asm volatile ("sti");
0380   while (count == *counter)
0381     asm volatile ("pause");
0382   asm volatile ("cli");
0383   set_idt_descriptor (0x20, &old_timer);
0384   enable_idt ();
0385 #endif
0386 
0387   tsc_delay_usec (50000);      /* wait 50 milliseconds */
0388 }
0389 
0390 /* Initialize and identify the ATA drives in the system. */
0391 bool
0392 ata_init (void)
0393 {
0394   uint32 bus, drive, i;
0395 
0396   i = 0;
0397   bus = ATA_BUS_PRIMARY;
0398   drive = ATA_DRIVE_MASTER;
0399   pata_drives[i].ata_type = ata_identify (bus, drive);
0400   pata_drives[i].ata_bus = bus;
0401   pata_drives[i].ata_drive = drive;
0402 
0403   i = 1;
0404   bus = ATA_BUS_PRIMARY;
0405   drive = ATA_DRIVE_SLAVE;
0406   pata_drives[i].ata_type = ata_identify (bus, drive);
0407   pata_drives[i].ata_bus = bus;
0408   pata_drives[i].ata_drive = drive;
0409 
0410   i = 2;
0411   bus = ATA_BUS_SECONDARY;
0412   drive = ATA_DRIVE_MASTER;
0413   pata_drives[i].ata_type = ata_identify (bus, drive);
0414   pata_drives[i].ata_bus = bus;
0415   pata_drives[i].ata_drive = drive;
0416 
0417   i = 3;
0418   bus = ATA_BUS_SECONDARY;
0419   drive = ATA_DRIVE_SLAVE;
0420   pata_drives[i].ata_type = ata_identify (bus, drive);
0421   pata_drives[i].ata_bus = bus;
0422   pata_drives[i].ata_drive = drive;
0423 
0424   if (mp_ISA_PC) {
0425     set_vector_handler ((ATA_IRQ_PRIMARY - 8) + PIC2_BASE_IRQ,
0426                         ata_irq_handler);
0427     set_vector_handler ((ATA_IRQ_SECONDARY - 8) + PIC2_BASE_IRQ,
0428                         ata_irq_handler);
0429   } else {
0430     IOAPIC_map_GSI (IRQ_to_GSI (mp_ISA_bus_id, ATA_IRQ_PRIMARY),
0431                     ATA_VECTOR_PRIMARY, 0xFF00000000000800LL);
0432     IOAPIC_map_GSI (IRQ_to_GSI (mp_ISA_bus_id, ATA_IRQ_SECONDARY),
0433                     ATA_VECTOR_SECONDARY, 0xFF00000000000800LL);
0434     set_vector_handler (ATA_VECTOR_PRIMARY, ata_irq_handler);
0435     set_vector_handler (ATA_VECTOR_SECONDARY, ata_irq_handler);
0436   }
0437 
0438   return TRUE;
0439 }
0440 
0441 u64 atapi_cycles=0, atapi_count=0, atapi_max=0, atapi_min=~0LL;
0442 #define ATAPI_MEASURE_START                                     \
0443   u64 _atapi_start, _atapi_finish;                              \
0444   RDTSC (_atapi_start);
0445 #define ATAPI_MEASURE_FINISH                                    \
0446   RDTSC (_atapi_finish);                                        \
0447   atapi_cycles += _atapi_finish - _atapi_start;                 \
0448   atapi_count++;                                                \
0449   if (_atapi_finish - _atapi_start > atapi_max) {               \
0450     atapi_max = _atapi_finish - _atapi_start;                   \
0451   }                                                             \
0452   if (_atapi_finish - _atapi_start < atapi_min) {               \
0453     atapi_min = _atapi_finish - _atapi_start;                   \
0454   }
0455 
0456 
0457 /* ************************************************** */
0458 /* ATAPI */
0459 
0460 /* ATAPI is essentially SCSI commands over ATA. */
0461 
0462 static u64 atapi_bytes = 0, atapi_timestamps = 0;
0463 
0464 /* Indicate which IRQs to measure response time */
0465 #define FIRST
0466 #define SECOND
0467 
0468 /* Use the ATAPI protocol to read a single sector from the given
0469  * bus/drive into the buffer. */
0470 int
0471 _atapi_drive_read_sector (uint32 bus, uint32 drive, uint32 lba, uint8 *buffer)
0472 {
0473   /* 0xA8 is READ SECTORS command byte. */
0474   uint8 read_cmd[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
0475   uint8 status;
0476   int size, fake_size;
0477   task_id cpu = 0;
0478 
0479   ata_grab ();
0480 
0481   DLOG ("atapi_drive_read_sector(%X,%X,%X,%p)", bus, drive, lba,
0482         buffer);
0483 
0484   outb (drive & (1 << 4), ATA_DRIVE_SELECT (bus));      /* select drive (only slavebit needed) */
0485   ATA_SELECT_DELAY (bus);
0486   outb (0x0, ATA_FEATURES (bus));       /* PIO mode */
0487   outb (ATAPI_SECTOR_SIZE & 0xFF, ATA_ADDRESS2 (bus));
0488   outb (ATAPI_SECTOR_SIZE >> 8, ATA_ADDRESS3 (bus));
0489   outb (0xA0, ATA_COMMAND (bus));       /* ATA PACKET command */
0490 
0491   while ((status = inb (ATA_COMMAND (bus))) & 0x80)     /* BUSY */
0492     asm volatile ("pause");
0493 
0494   while (!((status = inb (ATA_COMMAND (bus))) & 0x8) && !(status & 0x1))
0495     asm volatile ("pause");
0496   /* DRQ or ERROR set */
0497   if (status & 0x1) {
0498     size = -1;
0499     goto cleanup;
0500   }
0501 
0502   read_cmd[9] = 1;              /* 1 sector */
0503   read_cmd[2] = (lba >> 0x18) & 0xFF;   /* most sig. byte of LBA */
0504   read_cmd[3] = (lba >> 0x10) & 0xFF;
0505   read_cmd[4] = (lba >> 0x08) & 0xFF;
0506   read_cmd[5] = (lba >> 0x00) & 0xFF;   /* least sig. byte of LBA */
0507 
0508   /* Send ATAPI/SCSI command */
0509   outsw (ATA_DATA (bus), (uint16 *) read_cmd, 6);
0510 
0511   /* Wait for IRQ. */
0512   if (sched_enabled) {
0513     /* Switch to IO-VCPU */
0514     cpu = lookup_TSS (str ())->cpu;
0515     set_iovcpu (str (), IOVCPU_CLASS_ATA | IOVCPU_CLASS_CDROM);
0516     extern vcpu *vcpu_lookup (int);
0517     vcpu_lookup (lookup_TSS (str ())->cpu)->T = vcpu_lookup (cpu)->T;
0518 
0519 #ifdef FIRST
0520     ATAPI_MEASURE_START;
0521     u64 finish;
0522     RDTSC (irq_start);
0523 #else
0524     irq_start = 0;
0525 #endif
0526     schedule ();
0527 #ifdef FIRST
0528     RDTSC (finish);
0529     irq_turnaround += finish - irq_start;
0530     ATAPI_MEASURE_FINISH;
0531 #endif
0532   } else
0533     ata_poll_for_irq (bus);
0534 
0535   /* Wait for DRQ to set */
0536   while (!(inb (ATA_COMMAND (bus)) & 0x08))
0537     asm volatile ("pause");
0538 
0539   /* Read actual size */
0540   size =
0541     (((int) inb (ATA_ADDRESS3 (bus))) << 8) |
0542     (int) (inb (ATA_ADDRESS2 (bus)));
0543 
0544   DLOG ("atapi_drive_read_sector(%X,%X,%X,%p): actual size = %X",
0545         bus, drive, lba, buffer, size);
0546 
0547   /* Workaround possible size-reporting bug in hardware */
0548   if (size > ATAPI_SECTOR_SIZE)
0549     size = ATAPI_SECTOR_SIZE;
0550 
0551   /* Read data */
0552   insw (ATA_DATA (bus), buffer, size / 2);
0553 
0554   /* Wait for IRQ indicating next transfer ready.  It will be a
0555    * zero-byte transfer but we must still wait for the IRQ.*/
0556   if (sched_enabled) {
0557     /* Return to Main VCPU */
0558     lookup_TSS (str ())->cpu = cpu;
0559 
0560 #ifdef SECOND
0561     ATAPI_MEASURE_START;
0562     u64 finish;
0563     RDTSC (irq_start);
0564 #else
0565     irq_start = 0;
0566 #endif
0567     schedule ();
0568 #ifdef SECOND
0569     RDTSC (finish);
0570     irq_turnaround += finish - irq_start;
0571     ATAPI_MEASURE_FINISH;
0572 #endif
0573   } else
0574     ata_poll_for_irq (bus);
0575 
0576   /* Read size of "fake" transfer (may be 0) */
0577   fake_size =
0578     (((int) inb (ATA_ADDRESS3 (bus))) << 8) |
0579     (int) (inb (ATA_ADDRESS2 (bus)));
0580 
0581   DLOG ("atapi_drive_read_sector(%X,%X,%X,%p): fake size = %X",
0582         bus, drive, lba, buffer, fake_size);
0583 
0584   /* At this point we already have read all our data, but the hardware
0585    * may still report the same size value as before.  It is up to us
0586    * to know that this second IRQ fired but there is no more data to
0587    * be read. */
0588 
0589   /* To be sure, if the hardware sends me less than a sector at a
0590    * time, the above code is broken.  Not sure that will be an
0591    * issue. */
0592 
0593   /* Wait for BSY and DRQ to clear */
0594   while ((status = inb (ATA_COMMAND (bus))) & 0x88)
0595     asm volatile ("pause");
0596 
0597  cleanup:
0598   ata_release ();
0599   return size;
0600 }
0601 
0602 /* instrumentation variables */
0603 u64 atapi_sector_read_time = 0, atapi_sector_cpu_time = 0;
0604 u64 atapi_req_interval = 0;
0605 static u64 prev_req = 0;
0606 u32 atapi_req_count = 0;
0607 u64 atapi_req_diff;
0608 
0609 int
0610 atapi_drive_read_sector (uint32 bus, uint32 drive, uint32 lba, uint8 * buffer)
0611 {
0612   int size;
0613   u64 start = 0, finish;
0614   u64 vstart = 0, vfinish;
0615 
0616   /* begin instrumentation */
0617   if (sched_enabled) {
0618     RDTSC (start);
0619     vstart = vcpu_current_vtsc ();
0620 
0621     /* interval between sector requests */
0622     if (prev_req)
0623       atapi_req_interval = start - prev_req;
0624     prev_req = start;
0625   }
0626 
0627   /* invoke actual function */
0628   size = _atapi_drive_read_sector (bus, drive, lba, buffer);
0629 
0630   if (sched_enabled) {
0631     /* conclude instrumentation */
0632     RDTSC (finish);
0633     vfinish = vcpu_current_vtsc ();
0634 
0635     /* record size and timing info */
0636     atapi_bytes += size;
0637     atapi_timestamps += finish - start;
0638     atapi_sector_read_time += finish - start;
0639     atapi_sector_cpu_time += vfinish - vstart;
0640 
0641     /* req_diff measures the time between the end of one request and the
0642      * beginning of the next request */
0643     atapi_req_diff += atapi_req_interval - (finish - start);
0644     atapi_req_count++;
0645   }
0646 
0647   return size;
0648 }
0649 
0650 extern u32
0651 atapi_sample_bps (void)
0652 {
0653   extern u32 tsc_freq_msec;
0654   u64 atapi_msec = div64_64 (atapi_timestamps, (u64) tsc_freq_msec);
0655   u32 bytes_sec = 0;
0656   if (atapi_msec)
0657     bytes_sec = (u32) div64_64 (atapi_bytes * 1000, atapi_msec);
0658   atapi_bytes = 0;
0659   atapi_timestamps = 0;
0660   return bytes_sec;
0661 }
0662 
0663 #include "module/header.h"
0664 
0665 static const struct module_ops mod_ops = {
0666   .init = ata_init
0667 };
0668 
0669 DEF_MODULE (storage___ata, "ATA/ATAPI driver", &mod_ops, {});
0670 
0671 /*
0672  * Local Variables:
0673  * indent-tabs-mode: nil
0674  * mode: C
0675  * c-file-style: "gnu"
0676  * c-basic-offset: 2
0677  * End:
0678  */
0679 
0680 /* vi: set et sw=2 sts=2: */