|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Copyright (c) 2008, Intel Corporation.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
35c908 |
* under the terms and conditions of the GNU Lesser General Public License,
|
|
Packit Service |
35c908 |
* version 2.1, as published by the Free Software Foundation.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
35c908 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
35c908 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
Packit Service |
35c908 |
* for more details.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
35c908 |
* along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
35c908 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
#include "utils.h"
|
|
Packit Service |
35c908 |
#include "adapt_impl.h"
|
|
Packit Service |
35c908 |
#include <linux/pci_regs.h>
|
|
Packit Service |
35c908 |
#include <pciaccess.h>
|
|
Packit Service |
35c908 |
#include <byteswap.h>
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
static void
|
|
Packit Service |
35c908 |
get_device_serial_number(struct pci_device *dev, struct hba_info *hba_info)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
pciaddr_t offset;
|
|
Packit Service |
35c908 |
u_int32_t pcie_cap_header;
|
|
Packit Service |
35c908 |
u_int16_t pcie_cap_id;
|
|
Packit Service |
35c908 |
u_int16_t status;
|
|
Packit Service |
35c908 |
u_int8_t cap_ptr;
|
|
Packit Service |
35c908 |
u_int32_t dword_low = 0;
|
|
Packit Service |
35c908 |
u_int32_t dword_high = 0;
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/* Default */
|
|
Packit Service |
35c908 |
snprintf(hba_info->SerialNumber,
|
|
Packit Service |
35c908 |
sizeof(hba_info->SerialNumber),
|
|
Packit Service |
35c908 |
"Unknown");
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Read the Status Register in the PCIe configuration
|
|
Packit Service |
35c908 |
* header space to see if the PCI Capability List is
|
|
Packit Service |
35c908 |
* supported by this device.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u16(dev, &status, PCI_STATUS);
|
|
Packit Service |
35c908 |
if (rc) {
|
|
Packit Service |
35c908 |
fprintf(stderr, "Failed reading PCI Status Register\n");
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
if (!(status & PCI_STATUS_CAP_LIST)) {
|
|
Packit Service |
35c908 |
printf("PCI capabilities are not supported\n");
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Read the offset (cap_ptr) of first entry in the capability list in
|
|
Packit Service |
35c908 |
* the PCI configuration space.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u8(dev, &cap_ptr, PCI_CAPABILITY_LIST);
|
|
Packit Service |
35c908 |
if (rc) {
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"Failed reading PCI Capability List Register\n");
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
offset = cap_ptr;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/* Search for the PCIe capability */
|
|
Packit Service |
35c908 |
while (offset) {
|
|
Packit Service |
35c908 |
u_int8_t cap_id;
|
|
Packit Service |
35c908 |
u_int8_t next_cap;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u8(dev, &cap_id,
|
|
Packit Service |
35c908 |
offset + PCI_CAP_LIST_ID);
|
|
Packit Service |
35c908 |
if (rc) {
|
|
Packit Service |
35c908 |
#if defined(__x86_64__)
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"Failed reading capability ID at 0x%lx\n",
|
|
Packit Service |
35c908 |
offset + PCI_CAP_LIST_ID);
|
|
Packit Service |
35c908 |
#elif defined(__i386__)
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"Failed reading capability ID at 0x%llx\n",
|
|
Packit Service |
35c908 |
offset + PCI_CAP_LIST_ID);
|
|
Packit Service |
35c908 |
#endif
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
if (cap_id != PCI_CAP_ID_EXP) {
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u8(dev, &next_cap,
|
|
Packit Service |
35c908 |
offset + PCI_CAP_LIST_NEXT);
|
|
Packit Service |
35c908 |
if (rc) {
|
|
Packit Service |
35c908 |
#if defined(__x86_64__)
|
|
Packit Service |
35c908 |
fprintf(stderr, "Failed reading next capability "
|
|
Packit Service |
35c908 |
"offset at 0x%lx\n",
|
|
Packit Service |
35c908 |
offset + PCI_CAP_LIST_NEXT);
|
|
Packit Service |
35c908 |
#elif defined(__i386__)
|
|
Packit Service |
35c908 |
fprintf(stderr, "Failed reading next capability "
|
|
Packit Service |
35c908 |
"offset at 0x%llx\n",
|
|
Packit Service |
35c908 |
offset + PCI_CAP_LIST_NEXT);
|
|
Packit Service |
35c908 |
#endif
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
offset = (pciaddr_t)next_cap;
|
|
Packit Service |
35c908 |
continue;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* PCIe Capability Structure exists!
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* The first PCIe extended capability is located at
|
|
Packit Service |
35c908 |
* offset 0x100 in the device configuration space.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
offset = 0x100;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
do {
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u32(dev, &pcie_cap_header,
|
|
Packit Service |
35c908 |
offset);
|
|
Packit Service |
35c908 |
if (rc) {
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"Failed reading PCIe config header\n");
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/* Get the PCIe Extended Capability ID */
|
|
Packit Service |
35c908 |
pcie_cap_id = pcie_cap_header & 0xffff;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
if (pcie_cap_id != PCI_EXT_CAP_ID_DSN) {
|
|
Packit Service |
35c908 |
/* Get the offset of the next capability */
|
|
Packit Service |
35c908 |
offset = (pciaddr_t)pcie_cap_header >> 20;
|
|
Packit Service |
35c908 |
continue;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Found the serial number register!
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u32(dev,
|
|
Packit Service |
35c908 |
&dword_low, offset + 4);
|
|
Packit Service |
35c908 |
rc = pci_device_cfg_read_u32(dev,
|
|
Packit Service |
35c908 |
&dword_high, offset + 8);
|
|
Packit Service |
35c908 |
snprintf(hba_info->SerialNumber,
|
|
Packit Service |
35c908 |
sizeof(hba_info->SerialNumber),
|
|
Packit Service |
35c908 |
"%02X%02X%02X%02X%02X%02X\n",
|
|
Packit Service |
35c908 |
dword_high >> 24, (dword_high >> 16) & 0xff,
|
|
Packit Service |
35c908 |
(dword_high >> 8) & 0xff, (dword_low >> 16) & 0xff,
|
|
Packit Service |
35c908 |
(dword_low >> 8) & 0xff, dword_low & 0xff);
|
|
Packit Service |
35c908 |
break;
|
|
Packit Service |
35c908 |
} while (offset);
|
|
Packit Service |
35c908 |
break;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
static void
|
|
Packit Service |
35c908 |
get_pci_device_info(struct pci_device *dev, struct hba_info *hba_info)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
const char *name;
|
|
Packit Service |
35c908 |
u_int8_t revision;
|
|
Packit Service |
35c908 |
char *unknown = "Unknown";
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
name = pci_device_get_vendor_name(dev);
|
|
Packit Service |
35c908 |
if (!name)
|
|
Packit Service |
35c908 |
name = unknown;
|
|
Packit Service |
35c908 |
sa_strncpy_safe(hba_info->Manufacturer,
|
|
Packit Service |
35c908 |
sizeof(hba_info->Manufacturer),
|
|
Packit Service |
35c908 |
name, sizeof(hba_info->Manufacturer));
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
name = pci_device_get_device_name(dev);
|
|
Packit Service |
35c908 |
if (!name)
|
|
Packit Service |
35c908 |
name = unknown;
|
|
Packit Service |
35c908 |
sa_strncpy_safe(hba_info->ModelDescription,
|
|
Packit Service |
35c908 |
sizeof(hba_info->ModelDescription),
|
|
Packit Service |
35c908 |
name, sizeof(hba_info->ModelDescription));
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Reading hardware revision from PCIe
|
|
Packit Service |
35c908 |
* configuration header space.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
pci_device_cfg_read_u8(dev, &revision, PCI_REVISION_ID);
|
|
Packit Service |
35c908 |
snprintf(hba_info->HardwareVersion,
|
|
Packit Service |
35c908 |
sizeof(hba_info->HardwareVersion),
|
|
Packit Service |
35c908 |
"%02x", revision);
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
hba_info->NumberOfPorts = 1;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Searching for serial number in PCIe extended
|
|
Packit Service |
35c908 |
* capabilities space
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
get_device_serial_number(dev, hba_info);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
HBA_STATUS
|
|
Packit Service |
35c908 |
find_pci_device(struct hba_info *hba_info)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
struct pci_device_iterator *iterator;
|
|
Packit Service |
35c908 |
struct pci_device *dev;
|
|
Packit Service |
35c908 |
struct pci_slot_match match;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = pci_system_init();
|
|
Packit Service |
35c908 |
if (rc) {
|
|
Packit Service |
35c908 |
fprintf(stderr, "pci_system_init failed\n");
|
|
Packit Service |
35c908 |
return HBA_STATUS_ERROR;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
match.domain = hba_info->domain;
|
|
Packit Service |
35c908 |
match.bus = hba_info->bus;
|
|
Packit Service |
35c908 |
match.dev = hba_info->dev;
|
|
Packit Service |
35c908 |
match.func = hba_info->func;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
iterator = pci_slot_match_iterator_create(&match);
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
for (;;) {
|
|
Packit Service |
35c908 |
dev = pci_device_next(iterator);
|
|
Packit Service |
35c908 |
if (!dev)
|
|
Packit Service |
35c908 |
break;
|
|
Packit Service |
35c908 |
get_pci_device_info(dev, hba_info);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
pci_system_cleanup();
|
|
Packit Service |
35c908 |
return HBA_STATUS_OK;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|