Blame pci.c

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