From 5797d59f94541e1d3c4c0e4b0373a46c09f43edf Mon Sep 17 00:00:00 2001 From: Alexander Coers Date: Fri, 1 Dec 2017 16:00:01 +0100 Subject: [PATCH] ATA: Support for Highpoint HPT36x/37x PCI controller Signed-off-by: Augustin Cavalier Fixes #13819. Some style fixes by me. --- build/jam/packages/Haiku | 4 +- build/jam/packages/HaikuBootstrap | 3 +- src/add-ons/kernel/busses/ata/Jamfile | 1 + .../busses/ata/highpoint_ide_pci/Jamfile | 7 + .../ata/highpoint_ide_pci/highpoint_ata.h | 51 ++ .../highpoint_ide_pci/highpoint_ide_pci.cpp | 444 ++++++++++++++++++ 6 files changed, 507 insertions(+), 3 deletions(-) create mode 100644 src/add-ons/kernel/busses/ata/highpoint_ide_pci/Jamfile create mode 100644 src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ata.h create mode 100644 src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ide_pci.cpp diff --git a/build/jam/packages/Haiku b/build/jam/packages/Haiku index 4f41cb87e1..fb9dcb9c00 100644 --- a/build/jam/packages/Haiku +++ b/build/jam/packages/Haiku @@ -31,7 +31,7 @@ AddFilesToPackage add-ons kernel bus_managers : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; AddFilesToPackage add-ons kernel busses agp_gart : intel@x86,x86_64 ; AddFilesToPackage add-ons kernel busses ata - : generic_ide_pci it8211 legacy_sata silicon_image_3112 ide_isa@x86 ; + : generic_ide_pci it8211 legacy_sata silicon_image_3112 highpoint_ide_pci ide_isa@x86 ; AddFilesToPackage add-ons kernel busses random : virtio_rng ; AddFilesToPackage add-ons kernel busses scsi : ahci virtio_scsi ; @@ -198,7 +198,7 @@ AddBootModuleSymlinksToPackage legacy_sata locked_pool openpic@ppc packagefs pci - scsi scsi_cd scsi_disk scsi_periph silicon_image_3112 + scsi scsi_cd scsi_disk scsi_periph silicon_image_3112 highpoint_ide_pci usb usb_disk ehci ohci uhci xhci virtio virtio_block virtio_pci virtio_scsi ; diff --git a/build/jam/packages/HaikuBootstrap b/build/jam/packages/HaikuBootstrap index ca41edd7b9..ac3cbe4213 100644 --- a/build/jam/packages/HaikuBootstrap +++ b/build/jam/packages/HaikuBootstrap @@ -31,7 +31,7 @@ AddFilesToPackage add-ons kernel bus_managers : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; AddFilesToPackage add-ons kernel busses agp_gart : intel@x86,x86_64 ; AddFilesToPackage add-ons kernel busses ata - : generic_ide_pci it8211 legacy_sata silicon_image_3112 ide_isa@x86 ; + : generic_ide_pci it8211 legacy_sata silicon_image_3112 highpoint_ide_pci ide_isa@x86 ; AddFilesToPackage add-ons kernel busses scsi : ahci virtio_scsi ; AddFilesToPackage add-ons kernel busses usb : uhci ohci ehci ; @@ -168,6 +168,7 @@ AddBootModuleSymlinksToPackage openpic@ppc ata_adapter@ata locked_pool scsi_periph ahci generic_ide_pci it8211 legacy_sata silicon_image_3112 + highpoint_ide_pci ide_isa@x86 uhci ohci ehci scsi_cd scsi_disk usb_disk diff --git a/src/add-ons/kernel/busses/ata/Jamfile b/src/add-ons/kernel/busses/ata/Jamfile index 2159c1b5d0..8bab4a95ac 100644 --- a/src/add-ons/kernel/busses/ata/Jamfile +++ b/src/add-ons/kernel/busses/ata/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel busses ata ; SubInclude HAIKU_TOP src add-ons kernel busses ata generic_ide_pci ; +SubInclude HAIKU_TOP src add-ons kernel busses ata highpoint_ide_pci ; SubInclude HAIKU_TOP src add-ons kernel busses ata ide_isa ; SubInclude HAIKU_TOP src add-ons kernel busses ata it8211 ; SubInclude HAIKU_TOP src add-ons kernel busses ata promise_tx2 ; diff --git a/src/add-ons/kernel/busses/ata/highpoint_ide_pci/Jamfile b/src/add-ons/kernel/busses/ata/highpoint_ide_pci/Jamfile new file mode 100644 index 0000000000..6cbfcf2208 --- /dev/null +++ b/src/add-ons/kernel/busses/ata/highpoint_ide_pci/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel busses ata highpoint_ide_pci ; + +UsePrivateHeaders drivers kernel ; + +KernelAddon highpoint_ide_pci : + highpoint_ide_pci.cpp + ; diff --git a/src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ata.h b/src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ata.h new file mode 100644 index 0000000000..063e898ccb --- /dev/null +++ b/src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ata.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017, Alexander Coers. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _HIGHPOINT_ATA_H +#define _HIGHPOINT_ATA_H + +#include + + +enum { + ATA_MWORD_DMA0 = 0x00, + ATA_MWORD_DMA1 = 0x01, + ATA_MWORD_DMA2 = 0x02, + ATA_ULTRA_DMA0 = 0x10, + ATA_ULTRA_DMA1 = 0x11, + ATA_ULTRA_DMA2 = 0x12, + ATA_ULTRA_DMA3 = 0x13, + ATA_ULTRA_DMA4 = 0x14, + ATA_ULTRA_DMA5 = 0x15, + ATA_ULTRA_DMA6 = 0x16 +}; + +enum { + CFG_HPT366_OLD, + CFG_HPT366, + CFG_HPT370, + CFG_HPT372, + CFG_HPT374, + CFG_HPTUnknown // no supported option found +}; + +#define ATA_HIGHPOINT_ID 0x1103 + +#define ATA_HPT366 0x0004 +#define ATA_HPT372 0x0005 +#define ATA_HPT302 0x0006 +#define ATA_HPT371 0x0007 +#define ATA_HPT374 0x0008 + +struct HPT_controller_info { + uint16 deviceID; + uint8 revisionID; + uint8 function; + bool configuredDMA; // is DMA already configured + int configOption; // some HPT devices need different settings + uint8 maxDMA; // see enum +}; + + +#endif // _HIGHPOINT_ATA_H diff --git a/src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ide_pci.cpp b/src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ide_pci.cpp new file mode 100644 index 0000000000..7a063ea5fb --- /dev/null +++ b/src/add-ons/kernel/busses/ata/highpoint_ide_pci/highpoint_ide_pci.cpp @@ -0,0 +1,444 @@ +/* + * 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 TRACE(a...) dprintf("Highpoint-IDE: " a) + +//#define TRACE_EXT_HIGHPOINT +#ifdef TRACE_EXT_HIGHPOINT +#define TRACE_EXT(a...) dprintf("Highpoint-IDE (ext): " a) +#else +#define TRACE_EXT(a...) +#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_EXT("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_EXT("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_EXT("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_EXT("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_EXT("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_EXT("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_EXT("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_EXT("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_EXT("start_dma()\n"); + + return sATAAdapter->start_dma((ata_adapter_channel_info *)channel_cookie); +} + + +static status_t +finish_dma(void *channel_cookie) +{ + TRACE_EXT("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=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; + + TRACE("init_controller(): 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)); + TRACE("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; + } + } + TRACE("supports_device(): 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 +};