diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci.c b/src/add-ons/kernel/busses/scsi/ahci/ahci.c index 51494bea96..07ae98fde3 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci.c +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci.c @@ -20,6 +20,36 @@ device_manager_info *gDeviceManager; +device_info sSupportedDevices[] = +{ + { 0x197b, 0x2360, "JMicron JMB360" }, + { 0x197b, 0x2361, "JMicron JMB361" }, + { 0x197b, 0x2362, "JMicron JMB362" }, + { 0x197b, 0x2363, "JMicron JMB363" }, + { 0x197b, 0x2366, "JMicron JMB366" }, + { 0x8086, 0x27c0, "Intel ICH7 (IDE mode)" }, + { 0x8086, 0x27c1, "Intel ICH7 (AHCI mode)" }, + {} +}; + + +status_t +get_device_info(uint16 vendorID, uint16 deviceID, const char **name, uint32 *flags) +{ + device_info *info; + for (info = sSupportedDevices; info->vendor; info++) { + if (info->vendor == vendorID && info->device == deviceID) { + if (name) + *name = info->name; + if (flags) + *flags = info->flags; + return B_OK; + } + } + return B_ERROR; +} + + static status_t register_sim(device_node_handle parent) { @@ -58,42 +88,64 @@ register_sim(device_node_handle parent) // #pragma mark - - static float ahci_supports_device(device_node_handle parent, bool *_noConnection) { uint8 baseClass, subClass, classAPI; uint16 vendorID; uint16 deviceID; + bool isPCI; + const char *name; char *bus; TRACE("ahci_supports_device\n"); - if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, - false) != B_OK - || gDeviceManager->get_attr_uint8(parent, - PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) != B_OK - || gDeviceManager->get_attr_uint8(parent, - PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) != B_OK - || gDeviceManager->get_attr_uint8(parent, - PCI_DEVICE_API_ID_ITEM, &classAPI, false) != B_OK - || gDeviceManager->get_attr_uint16(parent, - PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, false) != B_OK - || gDeviceManager->get_attr_uint16(parent, - PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, false) != B_OK) - return B_ERROR; - - if (strcmp(bus, "pci") || baseClass != PCI_mass_storage - || subClass != PCI_sata || classAPI != PCI_sata_ahci) { - free(bus); + if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false) < B_OK) return 0.0f; + isPCI = !strcmp(bus, "pci"); + free(bus); + if (!isPCI) + return 0.0f; + + if (gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) < B_OK + || gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) < B_OK + || gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_API_ID_ITEM, &classAPI, false) < B_OK + || gDeviceManager->get_attr_uint16(parent, PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, false) < B_OK + || gDeviceManager->get_attr_uint16(parent, PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, false) < B_OK) + return 0.0f; + + if (get_device_info(vendorID, deviceID, &name, NULL) < B_OK) { + if (baseClass != PCI_mass_storage || subClass != PCI_sata || classAPI != PCI_sata_ahci) + return 0.0f; + TRACE("generic AHCI controller found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID); + return 0.8f; } - TRACE("controller found! vendor 0x%04x, device 0x%04x\n", - vendorID, deviceID); + if (vendorID == PCI_VENDOR_JMICRON) { + // JMicron uses the same device ID for SATA and PATA controllers, + // check if BAR5 exists to determine if it's a AHCI controller + uint8 bus, device, function; + pci_info info; + pci_module_info *pci; + size_t size = 0; + int i; + gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_BUS_ITEM, &bus, false); + gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_DEVICE_ITEM, &device, false); + gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_FUNCTION_ITEM, &function, false); + get_module(B_PCI_MODULE_NAME, (module_info **)&pci); + for (i = 0; B_OK == pci->get_nth_pci_info(i, &info); i++) { + if (info.bus == bus && info.device == device && info.function == function) { + size = info.u.h0.base_register_sizes[5]; + break; + } + } + put_module(B_PCI_MODULE_NAME); + if (size == 0) + return 0.0f; + } - free(bus); - return 0.5; + TRACE("AHCI controller %s found!\n", name); + return 1.0f; } @@ -156,6 +208,8 @@ ahci_init_driver(device_node_handle node, void *userCookie, void **_cookie) if (status != B_OK) return status; + TRACE("ahci_init_driver: gPCI %p, pciDevice %p\n", gPCI, pciDevice); + gDeviceManager->put_device_node(parent); *_userCookie = pciDevice; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp index 75cfa7cdbb..599e809672 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp @@ -20,6 +20,7 @@ AHCIController::AHCIController(device_node_handle node, pci_device_info *device) , fPCIDevice(device) , fPCIVendorID(0xffff) , fPCIDeviceID(0xffff) + , fFlags(0) , fCommandSlotCount(0) , fPortCountMax(0) , fPortCountAvail(0) @@ -69,6 +70,8 @@ AHCIController::Init() fInstanceCheck = create_port(1, sName); // --- Instance check workaround end + get_device_info(fPCIVendorID, fPCIDeviceID, NULL, &fFlags); + uchar capabilityOffset; status_t res = gPCI->find_pci_capability(fPCIDevice, PCI_cap_id_sata, &capabilityOffset); if (res == B_OK) { diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h index 059e6540b5..9ec950daed 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h @@ -40,6 +40,7 @@ private: pci_device_info* fPCIDevice; uint16 fPCIVendorID; uint16 fPCIDeviceID; + uint32 fFlags; volatile ahci_hba * fRegs; area_id fRegsArea; @@ -49,7 +50,6 @@ private: uint8 fIRQ; AHCIPort * fPort[32]; - // --- Instance check workaround begin port_id fInstanceCheck; // --- Instance check workaround end @@ -64,5 +64,4 @@ AHCIController::FlushPostedWrites() dummy = dummy; } - #endif // _AHCI_CONTROLLER_H diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h index 2b701254c6..ed727d6352 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h @@ -8,6 +8,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define AHCI_DEVICE_MODULE_NAME "busses/scsi/ahci/device_v1" #define AHCI_SIM_MODULE_NAME "busses/scsi/ahci/sim/v1" @@ -211,6 +215,16 @@ typedef struct { #define PRD_MAX_DATA_LENGTH 0x400000 /* 4 MB */ +typedef struct { + uint16 vendor; + uint16 device; + const char *name; + uint32 flags; +} device_info; + +status_t get_device_info(uint16 vendorID, uint16 deviceID, const char **name, uint32 *flags); + + extern scsi_sim_interface gAHCISimInterface; extern device_manager_info *gDeviceManager; extern pci_device_module_info *gPCI; @@ -224,6 +238,10 @@ extern scsi_for_sim_interface *gSCSI; #define PCI_VENDOR_JMICRON 0x197b #define PCI_JMICRON_CONTROLLER_CONTROL_1 0x40 +#ifdef __cplusplus +} +#endif + #ifdef __cplusplus template @@ -264,5 +282,4 @@ wait_until_clear(volatile uint32 *reg, uint32 bits, bigtime_t timeout) #endif /* __cplusplus */ - #endif /* _AHCI_DEFS_H */ diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp index 2998c4525a..eca0134bca 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp @@ -130,15 +130,19 @@ ahci_sim_init_bus(device_node_handle node, void *userCookie, void **_cookie) AHCIController *controller; status_t status; - TRACE("ahci_sim_init_bus, userCookie %p\n", userCookie); + TRACE("ahci_sim_init_bus: userCookie %p\n", userCookie); - // initialize parent (the bus) to get the PCI interface and device + TRACE("ahci_sim_init_bus: gPCI %p\n", gPCI); + + // initialize parent (the bus) to get the PCI device parent = gDeviceManager->get_parent(node); status = gDeviceManager->init_driver(parent, &pciDevice, NULL, NULL); gDeviceManager->put_device_node(parent); if (status != B_OK) return status; + TRACE("ahci_sim_init_bus: pciDevice %p\n", pciDevice); + controller = new(std::nothrow) AHCIController(node, pciDevice); if (!controller) return B_NO_MEMORY;