Blame pci.c

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