Warning, cross-references for /kernel/drivers/ata/ata.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
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
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
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 ata_info pata_drives[4];
0088
0089
0090
0091 static uint16 ata_current_task = 0;
0092
0093 static uint16 ata_waitqueue = 0;
0094
0095
0096
0097
0098
0099
0100
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
0124
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
0129 void
0130 ata_sreset (uint32 bus)
0131 {
0132 outb (0x02, ATA_DCR (bus));
0133 outb (0x00, ATA_DCR (bus));
0134 }
0135
0136
0137
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
0146
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));
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
0167 goto guess_identity;
0168 }
0169
0170
0171
0172
0173
0174 while ((status = inb (ATA_COMMAND (bus))) & 0x80)
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
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
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
0236
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 >> 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));
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
0273
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 >> 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));
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
0295
0296
0297
0298
0299 for (i = 0; i < 256; i++)
0300 outw (((uint16 *) buffer)[i], ATA_DATA (bus));
0301
0302 outb (0xE7, ATA_COMMAND (bus));
0303
0304 ret = 512;
0305
0306 cleanup:
0307 ata_release ();
0308 return ret;
0309 }
0310
0311
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
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
0343 if (ata_current_task)
0344 wakeup (ata_current_task);
0345
0346 unlock_kernel ();
0347 return 0;
0348 }
0349
0350
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
0360
0361
0362
0363 static void
0364 ata_poll_for_irq (uint32 bus)
0365 {
0366 #if 0
0367 uint32 count, *counter;
0368 idt_descriptor old_timer;
0369
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);
0388 }
0389
0390
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
0459
0460
0461
0462 static u64 atapi_bytes = 0, atapi_timestamps = 0;
0463
0464
0465 #define FIRST
0466 #define SECOND
0467
0468
0469
0470 int
0471 _atapi_drive_read_sector (uint32 bus, uint32 drive, uint32 lba, uint8 *buffer)
0472 {
0473
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));
0485 ATA_SELECT_DELAY (bus);
0486 outb (0x0, ATA_FEATURES (bus));
0487 outb (ATAPI_SECTOR_SIZE & 0xFF, ATA_ADDRESS2 (bus));
0488 outb (ATAPI_SECTOR_SIZE >> 8, ATA_ADDRESS3 (bus));
0489 outb (0xA0, ATA_COMMAND (bus));
0490
0491 while ((status = inb (ATA_COMMAND (bus))) & 0x80)
0492 asm volatile ("pause");
0493
0494 while (!((status = inb (ATA_COMMAND (bus))) & 0x8) && !(status & 0x1))
0495 asm volatile ("pause");
0496
0497 if (status & 0x1) {
0498 size = -1;
0499 goto cleanup;
0500 }
0501
0502 read_cmd[9] = 1;
0503 read_cmd[2] = (lba >> 0x18) & 0xFF;
0504 read_cmd[3] = (lba >> 0x10) & 0xFF;
0505 read_cmd[4] = (lba >> 0x08) & 0xFF;
0506 read_cmd[5] = (lba >> 0x00) & 0xFF;
0507
0508
0509 outsw (ATA_DATA (bus), (uint16 *) read_cmd, 6);
0510
0511
0512 if (sched_enabled) {
0513
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
0536 while (!(inb (ATA_COMMAND (bus)) & 0x08))
0537 asm volatile ("pause");
0538
0539
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
0548 if (size > ATAPI_SECTOR_SIZE)
0549 size = ATAPI_SECTOR_SIZE;
0550
0551
0552 insw (ATA_DATA (bus), buffer, size / 2);
0553
0554
0555
0556 if (sched_enabled) {
0557
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
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
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594 while ((status = inb (ATA_COMMAND (bus))) & 0x88)
0595 asm volatile ("pause");
0596
0597 cleanup:
0598 ata_release ();
0599 return size;
0600 }
0601
0602
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
0617 if (sched_enabled) {
0618 RDTSC (start);
0619 vstart = vcpu_current_vtsc ();
0620
0621
0622 if (prev_req)
0623 atapi_req_interval = start - prev_req;
0624 prev_req = start;
0625 }
0626
0627
0628 size = _atapi_drive_read_sector (bus, drive, lba, buffer);
0629
0630 if (sched_enabled) {
0631
0632 RDTSC (finish);
0633 vfinish = vcpu_current_vtsc ();
0634
0635
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
0642
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
0673
0674
0675
0676
0677
0678
0679
0680