refactor: isrm to centeralize interrupt/irq resources management.
[lunaix-os.git] / lunaix-os / hal / ahci / ata.c
1 #include <hal/ahci/ahci.h>
2 #include <hal/ahci/hba.h>
3 #include <hal/ahci/sata.h>
4
5 #include <lunaix/mm/valloc.h>
6 #include <lunaix/mm/vmm.h>
7 #include <lunaix/spike.h>
8
9 void
10 sata_read_error(struct hba_port* port)
11 {
12     uint32_t tfd = port->regs[HBA_RPxTFD];
13     port->device->last_result.sense_key = (tfd & 0xf000) >> 12;
14     port->device->last_result.error = (tfd & 0x0f00) >> 8;
15     port->device->last_result.status = tfd & 0x00ff;
16 }
17
18 int
19 __sata_buffer_io(struct hba_device* dev,
20                  uint64_t lba,
21                  void* buffer,
22                  uint32_t size,
23                  int write)
24 {
25     assert_msg(((uintptr_t)buffer & 0x3) == 0, "HBA: Bad buffer alignment");
26
27     struct hba_port* port = dev->port;
28     struct hba_cmdh* header;
29     struct hba_cmdt* table;
30     int slot = hba_prepare_cmd(port, &table, &header, buffer, size);
31
32     header->options |= HBA_CMDH_WRITE * (write == 1);
33
34     uint16_t count = ICEIL(size, port->device->block_size);
35     struct sata_reg_fis* fis = (struct sata_reg_fis*)table->command_fis;
36
37     if ((port->device->flags & HBA_DEV_FEXTLBA)) {
38         // 如果该设备支持48位LBA寻址
39         sata_create_fis(
40           fis, write ? ATA_WRITE_DMA_EXT : ATA_READ_DMA_EXT, lba, count);
41     } else {
42         sata_create_fis(fis, write ? ATA_WRITE_DMA : ATA_READ_DMA, lba, count);
43     }
44     /*
45           确保我们使用的是LBA寻址模式
46           注意:在ACS-3中(甚至在ACS-4),只有在(READ/WRITE)_DMA_EXT指令中明确注明了需要将这一位置位
47         而并没有在(READ/WRITE)_DMA注明。
48           但是这在ACS-2中是有的!于是这也就导致了先前的测试中,LBA=0根本无法访问,因为此时
49         的访问模式是在CHS下,也就是说LBA=0 => Sector=0,是非法的。
50           所以,我猜测,这要么是QEMU/VirtualBox根据ACS-2来编写的AHCI模拟,
51         要么是标准出错了(毕竟是working draft)
52     */
53     fis->dev = (1 << 6);
54
55     int is_ok = ahci_try_send(port, slot);
56
57     vfree_dma(table);
58     return is_ok;
59 }
60
61 int
62 sata_read_buffer(struct hba_device* dev,
63                  uint64_t lba,
64                  void* buffer,
65                  uint32_t size)
66 {
67     return __sata_buffer_io(dev, lba, buffer, size, 0);
68 }
69
70 int
71 sata_write_buffer(struct hba_device* dev,
72                   uint64_t lba,
73                   void* buffer,
74                   uint32_t size)
75 {
76     return __sata_buffer_io(dev, lba, buffer, size, 1);
77 }