summaryrefslogtreecommitdiff
path: root/kernel/src/devices/sata.c
blob: d091941863b18b360526dfabbc33472cb8021844 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <sata.h>
#include <libk/string.h>
#include <libk/stdio.h>
#include <heap.h>
#include <paging.h>
#include <pci.h>
#include <ahci.h>

// Check device type
static int check_type(HBA_PORT *port)
{
	uint32_t ssts = port->ssts;

	uint8_t ipm = (ssts >> 8) & 0x0F;
	uint8_t det = ssts & 0x0F;

	if (det != HBA_PORT_DET_PRESENT) // Check drive status
		return AHCI_DEV_NULL;
	if (ipm != HBA_PORT_IPM_ACTIVE)
		return AHCI_DEV_NULL;

	switch (port->sig) {
	case SATA_SIG_ATAPI:
		return AHCI_DEV_SATAPI;
	case SATA_SIG_SEMB:
		return AHCI_DEV_SEMB;
	case SATA_SIG_PM:
		return AHCI_DEV_PM;
	default:
		return AHCI_DEV_SATA;
	}
}

void probe_port(HBA_MEM *abar)
{
	// Search disk in implemented ports
	uint32_t pi = abar->pi;
	int i = 0;
	while (i < 32) {
		if (pi & 1) {
			int dt = check_type(&abar->ports[i]);
			if (dt == AHCI_DEV_SATA) {
				printf("SATA drive found at port %d\n", i);
			} else if (dt == AHCI_DEV_SATAPI) {
				printf("SATAPI drive found at port %d\n", i);
			} else if (dt == AHCI_DEV_SEMB) {
				printf("SEMB drive found at port %d\n", i);
			} else if (dt == AHCI_DEV_PM) {
				printf("PM drive found at port %d\n", i);
			}
		}

		pi >>= 1;
		i++;
	}
}

void ahci()
{
	pci_dev_list_t *pos;
	list_for_each_entry(pos, (&pci_dev_list.list), list) {
		pci_dev_t *dev = &pos->dev->pci_dev;
		if (dev->class_ != 0x1 || dev->subclass != 0x6)
			continue;

		HBA_MEM *abar = (HBA_MEM *)(uint64_t)pos->dev->bar[5];
		printf("AHCI: %x\n", abar);
		map_addr((uint64_t)abar, (uint64_t)abar,
			 FLAG_PRESENT | FLAG_WRITABLE | FLAG_HUGE);

		probe_port(abar);
	}
}