AHCI drive detection problem on Parallels Desktop 6
Posted: Sun Jun 16, 2013 2:53 am
Hi guys,
I have a weird problem with AHCI drive detection on Parallels Desktop VM. My code follows explanation how to detect drives from http://wiki.osdev.org/AHCI. And it works pretty well on KVM/Qemu and VirtualBox. But on Parallels Desktop 6 I have a virtual drive (SATA 0:1) there which is not detected.
In particular the AHCI HBA is detected as PCI device, but every port from PI (ports implemented) has DET=0 and signature=0xFFFFFFFF. At the same time I know that Linux finds the drive in same VM configuration.
Here is my code:
Can you suggest my something? Thanks in advance.
I have a weird problem with AHCI drive detection on Parallels Desktop VM. My code follows explanation how to detect drives from http://wiki.osdev.org/AHCI. And it works pretty well on KVM/Qemu and VirtualBox. But on Parallels Desktop 6 I have a virtual drive (SATA 0:1) there which is not detected.
In particular the AHCI HBA is detected as PCI device, but every port from PI (ports implemented) has DET=0 and signature=0xFFFFFFFF. At the same time I know that Linux finds the drive in same VM configuration.
Here is my code:
Code: Select all
#define DRIVE_MAGIC 0x5105820974944592
#define MAX_DRIVES 8
#define MAX_PORTS 32
#define DET_PRESENT 3
#define IPM_ACTIVE 1
#define SIG_ATA 0x00000101
#define SIG_ATAPI 0xEB140101
#define SIG_SEMB 0xC33C0101
#define SIG_PM 0x96690101
struct drive {
uint64_t magic;
struct drive *next;
struct mutex lock;
int stamp;
int hba_pci_address : 24;
int hba_slot : 5;
int connected : 1;
int in_use : 1;
int used : 1;
};
struct port {
uint32_t clb, clbu, fb, fbu, is, ie, cmd, reserved0, tfd, sig, ssts, sctl;
uint32_t serr, sact, ci, sntf, fbs;
uint32_t reserved1[11], vendor[4];
};
struct hba {
uint32_t cap, ghc, is, pi, vs, ccc_ctl, ccc_pts, em_loc, em_ctl, cap2, bohc;
uint8_t reserved[0xA0-0x2C], vendor[0x100-0xA0];
struct port ports[];
};
static struct drive drives[MAX_DRIVES];
static struct ahci_driver driver;
static struct mutex lock;
const struct ahci_driver *get_ahci_driver(void) {
return &driver;
}
static void next_drive(int device, struct hba *hba, int port) {
LOG_DEBUG("SATA drive detected on port %d", port);
}
static void next_hba(int device) {
uint64_t bar5 = read_pci_field(device, PCI_FIELD_BAR5) & ~0x1FFF;
map_page(bar5, bar5, PAGE_MAPPING_WRITE | PAGE_MAPPING_PWT |
PAGE_MAPPING_PCD, 0);
struct hba *hba = (struct hba*)bar5;
uint32_t val = hba->ghc;
BIT_ARRAY_SET(&val, 0);
BIT_ARRAY_SET(&val, 31);
hba->ghc = val;
for (uint32_t pi = hba->pi, port = 0; port < MAX_PORTS; port++)
if (BIT_ARRAY_GET(&pi, port)) {
uint32_t val = hba->ports[port].cmd;
BIT_ARRAY_RESET(&val, 0);
BIT_ARRAY_RESET(&val, 4);
hba->ports[port].cmd = val;
uint32_t ssts = hba->ports[port].ssts;
uint32_t det = ssts & 0x0F, ipm = (ssts >> 8) & 0x0F;
uint32_t sig = hba->ports[port].sig;
if (det == DET_PRESENT && ipm == IPM_ACTIVE &&
sig != SIG_ATAPI && sig != SIG_SEMB && sig != SIG_PM)
next_drive(device, hba, port);
}
}
static err_code scan_devices(void) {
err_code err = ERR_NONE;
acquire_mutex(&lock);
for (int i = 0; i < MAX_DRIVES; i++)
if (drives[i].in_use)
drives[i].connected = false;
scan_pci(next_hba, PCI_TYPE_SERIAL_ATA);
for (int i = 0; i < MAX_DRIVES; i++)
if (drives[i].in_use && !drives[i].connected) {
drives[i].in_use = false;
}
release_mutex(&lock);
return err;
}
static err_code get_next_device(device_id *id) {
return ERR_NO_MORE;
}
void init_ahci(void) {
memset(drives, 0, sizeof(drives));
driver.storage_driver.driver = (struct driver) {
.type = DRIVER_TYPE_STORAGE, .scan_devices = scan_devices,
.get_next_device = get_next_device,
};
if (create_mutex(&lock))
LOG_ERROR("failed to create mutex")
else if (scan_devices())
LOG_ERROR("failed to scan drives")
else if (add_driver((struct driver*)&driver, NULL))
LOG_ERROR("failed to add driver")
else
LOG_DEBUG("done");
}