/* * Copyright 2017, Alexander Coers. All rights reserved. * Distributed under the terms of the MIT License. */ #include "highpoint_ata.h" #include #include #include #include #include #define INFO(a...) dprintf("Highpoint-IDE: " a) //#define TRACE_HIGHPOINT #ifdef TRACE_HIGHPOINT #define TRACE(a...) dprintf("Highpoint-IDE: " a) #define TRACE_ONLY #else #define TRACE(a...) #define TRACE_ONLY __attribute__((unused)) #endif #define HIGHPOINT_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ata/highpoint_ide_pci/driver_v1" #define HIGHPOINT_IDE_PCI_CHANNEL_MODULE_NAME "busses/ata/highpoint_ide_pci/channel/v1" static ata_for_controller_interface *sATA; static ata_adapter_interface *sATAAdapter; static device_manager_info *sDeviceManager; struct HPT_controller_info *HPT_info; // #pragma mark - helper functions static void set_channel(void *cookie, ata_channel channel) { TRACE("set_channel()\n"); sATAAdapter->set_channel((ata_adapter_channel_info *)cookie, channel); } static status_t write_command_block_regs(void *channel_cookie, ata_task_file *tf, ata_reg_mask mask) { TRACE("write_command_block_regs()\n"); return sATAAdapter->write_command_block_regs( (ata_adapter_channel_info *)channel_cookie, tf, mask); } static status_t read_command_block_regs(void *channel_cookie, ata_task_file *tf, ata_reg_mask mask) { TRACE("read_command_block_regs()\n"); return sATAAdapter->read_command_block_regs( (ata_adapter_channel_info *)channel_cookie, tf, mask); } static uint8 get_altstatus(void *channel_cookie) { TRACE("get_altstatus()\n"); return sATAAdapter->get_altstatus( (ata_adapter_channel_info *)channel_cookie); } static status_t write_device_control(void *channel_cookie, uint8 val) { TRACE("write_device_control()\n"); return sATAAdapter->write_device_control( (ata_adapter_channel_info *)channel_cookie, val); } static status_t write_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit) { TRACE("write_pio()\n"); return sATAAdapter->write_pio((ata_adapter_channel_info *)channel_cookie, data, count, force_16bit); } static status_t read_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit) { TRACE("read_pio()\n"); return sATAAdapter->read_pio((ata_adapter_channel_info *)channel_cookie, data, count, force_16bit); } static status_t prepare_dma(void *channel_cookie, const physical_entry *sg_list, size_t sg_list_count, bool to_device) { TRACE("prepare_dma()\n"); return sATAAdapter->prepare_dma((ata_adapter_channel_info *)channel_cookie, sg_list, sg_list_count, to_device); } static status_t start_dma(void *channel_cookie) { TRACE("start_dma()\n"); return sATAAdapter->start_dma((ata_adapter_channel_info *)channel_cookie); } static status_t finish_dma(void *channel_cookie) { TRACE("finish_dma()\n"); return sATAAdapter->finish_dma((ata_adapter_channel_info *)channel_cookie); } static status_t init_channel(device_node *node, void **channel_cookie) { status_t result; uint8 channel_index; TRACE("init_channel(): node: %p, cookie: %p\n", node, channel_cookie); #if 0 /* debug */ uint8 bus = 0, device = 0, function = 0; uint16 vendorID=0xffff, deviceID=0xffff; sDeviceManager->get_attr_uint16(node, B_DEVICE_VENDOR_ID, &vendorID, true); sDeviceManager->get_attr_uint16(node, B_DEVICE_ID, &deviceID, true); TRACE("init_channel():init_channel(): bus %3d, device %2d, function %2d: vendor %04x, device %04x\n", bus, device, function, vendorID, deviceID); if (vendorID != ATA_HIGHPOINT_ID) { TRACE ("unsupported! Vendor ID: %x\n",vendorID); return B_ERROR; } #endif result = sATAAdapter->init_channel(node, (ata_adapter_channel_info **)channel_cookie, sizeof(ata_adapter_channel_info), sATAAdapter->inthand); // from here we have valid channel... ata_adapter_channel_info *channel TRACE_ONLY = NULL; channel = (ata_adapter_channel_info *)*channel_cookie; if (sDeviceManager->get_attr_uint8(node, ATA_ADAPTER_CHANNEL_INDEX, &channel_index, false) != B_OK) { TRACE("init_channel(): channel not set, strange!\n"); return B_ERROR; } TRACE("init_channel(): channel command %x, control %x, result: %d \n", channel->command_block_base, channel->control_block_base, (int)result); TRACE("init_channel(): index #%d done. HPT_info deviceID: %04x, config option %x, " "revision %2d, function %2d \n", channel_index, HPT_info->deviceID, HPT_info->configOption, HPT_info->revisionID, HPT_info->function); return result; } static void uninit_channel(void *channel_cookie) { TRACE("uninit_channel()\n"); sATAAdapter->uninit_channel((ata_adapter_channel_info *)channel_cookie); } static void channel_removed(void *channel_cookie) { TRACE("channel_removed()\n"); sATAAdapter->channel_removed((ata_adapter_channel_info *)channel_cookie); } static status_t init_controller(device_node *node, ata_adapter_controller_info **cookie) { pci_device_module_info *pci; pci_device *pci_device; pci_info info; uint16 devID = 0xffff; uint8 revisionID = 0xff; uint8 function = 0xff; status_t result; // we need some our info structure here HPT_info = (struct HPT_controller_info *) malloc(sizeof(HPT_controller_info)); if (HPT_info == NULL) return B_NO_MEMORY; result = sATAAdapter->init_controller(node, cookie, sizeof(ata_adapter_controller_info)); if (result == B_OK) { // get device info device_node *parent = sDeviceManager->get_parent_node(node); sDeviceManager->get_driver(parent, (driver_module_info **)&pci, (void **)&pci_device); // read registers pci->get_pci_info(pci_device,&info); devID = info.device_id; revisionID = info.revision; function = info.function; HPT_info->deviceID = devID; HPT_info->revisionID = revisionID; HPT_info->function = function; INFO("found: device: %x, revision: %x, function: %x\n",devID,revisionID,function); // setting different config options if (devID == ATA_HPT366) { switch (revisionID) { case 0: HPT_info->configOption = CFG_HPT366_OLD; HPT_info->maxDMA = ATA_ULTRA_DMA4; break; case 1: case 2: HPT_info->configOption = CFG_HPT366; HPT_info->maxDMA = ATA_ULTRA_DMA4; break; case 3: HPT_info->configOption = CFG_HPT370; HPT_info->maxDMA = ATA_ULTRA_DMA5; break; case 5: HPT_info->configOption = CFG_HPT372; HPT_info->maxDMA = ATA_ULTRA_DMA6; break; default: HPT_info->configOption = CFG_HPTUnknown; HPT_info->maxDMA = ATA_ULTRA_DMA0; } } else { if (devID == ATA_HPT374) { HPT_info->configOption = CFG_HPT374; HPT_info->maxDMA = ATA_ULTRA_DMA6; } else { // all other versions use this config HPT_info->configOption = CFG_HPT372; HPT_info->maxDMA = ATA_ULTRA_DMA6; } } if (HPT_info->configOption == CFG_HPT366_OLD) { /* disable interrupt prediction */ pci->write_pci_config(pci_device, 0x51, 1, (pci->read_pci_config(pci_device, 0x51, 1) & ~0x80)); INFO("Highpoint-ATA: old revision found.\n"); } else { /* disable interrupt prediction */ pci->write_pci_config(pci_device, 0x51, 1, (pci->read_pci_config(pci_device, 0x51, 1) & ~0x03)); pci->write_pci_config(pci_device, 0x55, 1, (pci->read_pci_config(pci_device, 0x55, 1) & ~0x03)); /* enable interrupts */ pci->write_pci_config(pci_device, 0x5a, 1, (pci->read_pci_config(pci_device, 0x5a, 1) & ~0x10)); /* set clocks etc */ if (HPT_info->configOption < CFG_HPT372) { pci->write_pci_config(pci_device, 0x5b, 1, 0x22); } else { pci->write_pci_config(pci_device, 0x5b, 1, (pci->read_pci_config(pci_device, 0x5b, 1) & 0x01) | 0x20); } } } return result; } static void uninit_controller(ata_adapter_controller_info *controller) { TRACE("uninit_controller()\n"); free(HPT_info); sATAAdapter->uninit_controller(controller); } static void controller_removed(ata_adapter_controller_info *controller) { TRACE("controller_removed()\n"); return sATAAdapter->controller_removed(controller); } static status_t probe_controller(device_node *parent) { status_t result; result = sATAAdapter->probe_controller(parent, HIGHPOINT_IDE_PCI_CONTROLLER_MODULE_NAME, "highpoint_ide_pci", "Highpoint IDE PCI Controller", HIGHPOINT_IDE_PCI_CHANNEL_MODULE_NAME, true, true, // assume that command queuing works 1, // assume 16 bit alignment is enough 0xffff, // boundary is on 64k according to spec 0x10000, // up to 64k per S/G block according to spec false); // by default, compatibility mode is used, not for HPT! TRACE("probe_controller(): probe result: %x\n",(int)result); return result; } static float supports_device(device_node *parent) { TRACE("supports_device()\n"); const char *bus; uint16 baseClass, subClass; uint16 vendorID; uint16 deviceID; float result = -1.0f; // make sure parent is an PCI IDE mass storage host adapter device node if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK || sDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass, false) != B_OK || sDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass, false) != B_OK || sDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendorID, false) != B_OK || sDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID, false) != B_OK) return -1.0f; // No PCI bus OR no mass storage OR no Highpoint device = bail out if (vendorID != ATA_HIGHPOINT_ID) { TRACE("supports_device(): unsupported device: vendor ID: %x, deviceID: %x\n",vendorID, deviceID); return 0.0f; } // check if mass storage controller if ((subClass == PCI_ide) || (subClass == PCI_mass_storage_other)) { switch (deviceID) { case ATA_HPT302: // UDMA 6 case ATA_HPT366: // UDMA 4, Rev 0 & 2 // UDMA 5, Rev 3 // UDMA 6, Rev 5 case ATA_HPT371: case ATA_HPT372: case ATA_HPT374: // UDMA 6 result = 1.0f; break; default: // device not supported, should be covered by generic ata driver result = 0.0f; } } INFO("supporting device Vendor ID: %x, deviceID: %x, result %f\n", vendorID, deviceID, result); return result; } // #pragma mark - module dependencies module_dependency module_dependencies[] = { { ATA_FOR_CONTROLLER_MODULE_NAME, (module_info **)&sATA }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, { ATA_ADAPTER_MODULE_NAME, (module_info **)&sATAAdapter }, {} }; static ata_controller_interface channel_interface = { { { HIGHPOINT_IDE_PCI_CHANNEL_MODULE_NAME, 0, NULL }, NULL, // supports device NULL, // register device init_channel, uninit_channel, NULL, // register child devices NULL, // rescan channel_removed, }, &set_channel, &write_command_block_regs, &read_command_block_regs, &get_altstatus, &write_device_control, &write_pio, &read_pio, &prepare_dma, &start_dma, &finish_dma, }; static driver_module_info controller_interface = { { HIGHPOINT_IDE_PCI_CONTROLLER_MODULE_NAME, 0, NULL }, supports_device, probe_controller, (status_t (*)(device_node *, void **)) init_controller, (void (*)(void *)) uninit_controller, NULL, // register child devices NULL, // rescan (void (*)(void *)) controller_removed, }; module_info *modules[] = { (module_info *)&controller_interface, (module_info *)&channel_interface, NULL };