ATA: Support for Highpoint HPT36x/37x PCI controller
Signed-off-by: Augustin Cavalier <waddlesplash@gmail.com> Fixes #13819. Some style fixes by me.
This commit is contained in:
parent
841d719fc8
commit
5797d59f94
@ -31,7 +31,7 @@ AddFilesToPackage add-ons kernel bus_managers : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ;
|
||||
AddFilesToPackage add-ons kernel busses agp_gart : <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 <usb>ehci <usb>ohci <usb>uhci <usb>xhci
|
||||
virtio virtio_block virtio_pci virtio_scsi
|
||||
;
|
||||
|
@ -31,7 +31,7 @@ AddFilesToPackage add-ons kernel bus_managers : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ;
|
||||
AddFilesToPackage add-ons kernel busses agp_gart : <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 : <usb>uhci <usb>ohci <usb>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
|
||||
<usb>uhci <usb>ohci <usb>ehci
|
||||
scsi_cd scsi_disk usb_disk
|
||||
|
@ -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 ;
|
||||
|
7
src/add-ons/kernel/busses/ata/highpoint_ide_pci/Jamfile
Normal file
7
src/add-ons/kernel/busses/ata/highpoint_ide_pci/Jamfile
Normal file
@ -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
|
||||
;
|
@ -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 <SupportDefs.h>
|
||||
|
||||
|
||||
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
|
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright 2017, Alexander Coers. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "highpoint_ata.h"
|
||||
|
||||
#include <ata_adapter.h>
|
||||
#include <malloc.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#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
|
||||
};
|
Loading…
Reference in New Issue
Block a user