feat: disk read/write support for both ATA and ATAPI device
[lunaix-os.git] / lunaix-os / hal / ahci / ata.c
1 #include <hal/ahci/hba.h>
2 #include <hal/ahci/sata.h>
3
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/spike.h>
6
7 int
8 __sata_buffer_io(struct hba_port* port,
9                  uint64_t lba,
10                  void* buffer,
11                  uint32_t size,
12                  int write)
13 {
14     assert_msg(((uintptr_t)buffer & 0x3) == 0, "HBA: Bad buffer alignment");
15
16     struct hba_cmdh* header;
17     struct hba_cmdt* table;
18     int slot = hba_alloc_slot(port, &table, &header, 0);
19     int bitmask = 1 << slot;
20
21     // 确保端口是空闲的
22     wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY)));
23
24     port->regs[HBA_RPxIS] = 0;
25
26     table->entries[0] =
27       (struct hba_prdte){ .byte_count = size - 1, .data_base = buffer };
28     header->prdt_len = 1;
29     header->options |= HBA_CMDH_WRITE * (write == 1);
30
31     uint16_t count = size / port->device->block_size;
32     if (count == 0 && size < port->device->block_size) {
33         // 一个special case: 当count=0的时候,表示的是65536个区块会被传输
34         // 如果这个0是因为不够除而导致的,那么说明size太小了
35         goto fail;
36     }
37
38     struct sata_reg_fis* fis = table->command_fis;
39     if ((port->device->flags & HBA_DEV_FEXTLBA)) {
40         // 如果该设备支持48位LBA寻址
41         sata_create_fis(
42           fis, write ? ATA_WRITE_DMA_EXT : ATA_READ_DMA_EXT, lba, count);
43     } else {
44         sata_create_fis(fis, write ? ATA_WRITE_DMA : ATA_READ_DMA, lba, count);
45     }
46
47     port->regs[HBA_RPxCI] = bitmask;
48
49     wait_until(!(port->regs[HBA_RPxCI] & bitmask));
50
51     if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) {
52         // 有错误
53         sata_read_error(port);
54         goto fail;
55     }
56
57     vfree_dma(table);
58     return 1;
59
60 fail:
61     vfree_dma(table);
62     return 0;
63 }
64
65 int
66 sata_read_buffer(struct hba_port* port,
67                  uint64_t lba,
68                  void* buffer,
69                  uint32_t size)
70 {
71     return __sata_buffer_io(port, lba, buffer, size, 0);
72 }
73
74 int
75 sata_write_buffer(struct hba_port* port,
76                   uint64_t lba,
77                   void* buffer,
78                   uint32_t size)
79 {
80     return __sata_buffer_io(port, lba, buffer, size, 1);
81 }
82
83 void
84 sata_read_error(struct hba_port* port)
85 {
86     uint32_t tfd = port->regs[HBA_RPxTFD];
87     port->device->last_error = (tfd >> 8) & 0xff;
88 }