⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aic79xx_pci.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Product specific probe and attach routines for: *	aic7901 and aic7902 SCSI controllers * * Copyright (c) 1994-2001 Justin T. Gibbs. * Copyright (c) 2000-2002 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer *    substantially similar to the "NO WARRANTY" disclaimer below *    ("Disclaimer") and any redistribution must be conditioned upon *    including a substantially similar Disclaimer requirement for further *    binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names *    of any contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#77 $ * * $FreeBSD$ */#ifdef __linux__#include "aic79xx_osm.h"#include "aic79xx_inline.h"#else#include <dev/aic7xxx/aic79xx_osm.h>#include <dev/aic7xxx/aic79xx_inline.h>#endif#include "aic79xx_pci.h"static __inline uint64_tahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor){	uint64_t id;	id = subvendor	   | (subdevice << 16)	   | ((uint64_t)vendor << 32)	   | ((uint64_t)device << 48);	return (id);}#define ID_AIC7902_PCI_REV_A4		0x3#define ID_AIC7902_PCI_REV_B0		0x10#define SUBID_HP			0x0E11#define DEVID_9005_HOSTRAID(id) ((id) & 0x80)#define DEVID_9005_TYPE(id) ((id) & 0xF)#define		DEVID_9005_TYPE_HBA		0x0	/* Standard Card */#define		DEVID_9005_TYPE_HBA_2EXT	0x1	/* 2 External Ports */#define		DEVID_9005_TYPE_IROC		0x8	/* Raid(0,1,10) Card */#define		DEVID_9005_TYPE_MB		0xF	/* On Motherboard */#define DEVID_9005_MFUNC(id) ((id) & 0x10)#define DEVID_9005_PACKETIZED(id) ((id) & 0x8000)#define SUBID_9005_TYPE(id) ((id) & 0xF)#define		SUBID_9005_TYPE_HBA		0x0	/* Standard Card */#define		SUBID_9005_TYPE_MB		0xF	/* On Motherboard */#define SUBID_9005_AUTOTERM(id)	(((id) & 0x10) == 0)#define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20)#define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6)#define		SUBID_9005_SEEPTYPE_NONE	0x0#define		SUBID_9005_SEEPTYPE_4K		0x1static ahd_device_setup_t ahd_aic7901_setup;static ahd_device_setup_t ahd_aic7901A_setup;static ahd_device_setup_t ahd_aic7902_setup;static ahd_device_setup_t ahd_aic790X_setup;struct ahd_pci_identity ahd_pci_ident_table [] ={	/* aic7901 based controllers */	{		ID_AHA_29320A,		ID_ALL_MASK,		"Adaptec 29320A Ultra320 SCSI adapter",		ahd_aic7901_setup	},	{		ID_AHA_29320ALP,		ID_ALL_MASK,		"Adaptec 29320ALP Ultra320 SCSI adapter",		ahd_aic7901_setup	},	/* aic7902 based controllers */		{		ID_AHA_29320,		ID_ALL_MASK,		"Adaptec 29320 Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_29320B,		ID_ALL_MASK,		"Adaptec 29320B Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_29320LP,		ID_ALL_MASK,		"Adaptec 29320LP Ultra320 SCSI adapter",		ahd_aic7901A_setup	},	{		ID_AHA_39320,		ID_ALL_MASK,		"Adaptec 39320 Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_39320_B,		ID_ALL_MASK,		"Adaptec 39320 Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_39320A,		ID_ALL_MASK,		"Adaptec 39320A Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_39320D,		ID_ALL_MASK,		"Adaptec 39320D Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_39320D_HP,		ID_ALL_MASK,		"Adaptec (HP OEM) 39320D Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_39320D_B,		ID_ALL_MASK,		"Adaptec 39320D Ultra320 SCSI adapter",		ahd_aic7902_setup	},	{		ID_AHA_39320D_B_HP,		ID_ALL_MASK,		"Adaptec (HP OEM) 39320D Ultra320 SCSI adapter",		ahd_aic7902_setup	},	/* Generic chip probes for devices we don't know 'exactly' */	{		ID_AIC7901 & ID_9005_GENERIC_MASK,		ID_9005_GENERIC_MASK,		"Adaptec AIC7901 Ultra320 SCSI adapter",		ahd_aic7901_setup	},	{		ID_AIC7901A & ID_DEV_VENDOR_MASK,		ID_DEV_VENDOR_MASK,		"Adaptec AIC7901A Ultra320 SCSI adapter",		ahd_aic7901A_setup	},	{		ID_AIC7902 & ID_9005_GENERIC_MASK,		ID_9005_GENERIC_MASK,		"Adaptec AIC7902 Ultra320 SCSI adapter",		ahd_aic7902_setup	}};const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table);		#define	DEVCONFIG		0x40#define		PCIXINITPAT	0x0000E000ul#define			PCIXINIT_PCI33_66	0x0000E000ul#define			PCIXINIT_PCIX50_66	0x0000C000ul#define			PCIXINIT_PCIX66_100	0x0000A000ul#define			PCIXINIT_PCIX100_133	0x00008000ul#define	PCI_BUS_MODES_INDEX(devconfig)	\	(((devconfig) & PCIXINITPAT) >> 13)static const char *pci_bus_modes[] ={	"PCI bus mode unknown",	"PCI bus mode unknown",	"PCI bus mode unknown",	"PCI bus mode unknown",	"PCI-X 101-133Mhz",	"PCI-X 67-100Mhz",	"PCI-X 50-66Mhz",	"PCI 33 or 66Mhz"};#define		TESTMODE	0x00000800ul#define		IRDY_RST	0x00000200ul#define		FRAME_RST	0x00000100ul#define		PCI64BIT	0x00000080ul#define		MRDCEN		0x00000040ul#define		ENDIANSEL	0x00000020ul#define		MIXQWENDIANEN	0x00000008ul#define		DACEN		0x00000004ul#define		STPWLEVEL	0x00000002ul#define		QWENDIANSEL	0x00000001ul#define	DEVCONFIG1		0x44#define		PREQDIS		0x01#define	CSIZE_LATTIME		0x0c#define		CACHESIZE	0x000000fful#define		LATTIME		0x0000ff00ulstatic int	ahd_check_extport(struct ahd_softc *ahd);static void	ahd_configure_termination(struct ahd_softc *ahd,					  u_int adapter_control);static void	ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t pci){	uint64_t  full_id;	uint16_t  device;	uint16_t  vendor;	uint16_t  subdevice;	uint16_t  subvendor;	struct	  ahd_pci_identity *entry;	u_int	  i;	vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);	device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);	subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);	subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);	full_id = ahd_compose_id(device,				 vendor,				 subdevice,				 subvendor);	/*	 * Controllers, mask out the IROC/HostRAID bit	 */		full_id &= ID_ALL_IROC_MASK;	for (i = 0; i < ahd_num_pci_devs; i++) {		entry = &ahd_pci_ident_table[i];		if (entry->full_id == (full_id & entry->id_mask)) {			/* Honor exclusion entries. */			if (entry->name == NULL)				return (NULL);			return (entry);		}	}	return (NULL);}intahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry){	struct scb_data *shared_scb_data;	u_int		 command;	uint32_t	 devconfig;	uint16_t	 subvendor; 	int		 error;	shared_scb_data = NULL;	ahd->description = entry->name;	/*	 * Record if this is an HP board.	 */	subvendor = ahd_pci_read_config(ahd->dev_softc,					PCIR_SUBVEND_0, /*bytes*/2);	if (subvendor == SUBID_HP)		ahd->flags |= AHD_HP_BOARD;	error = entry->setup(ahd);	if (error != 0)		return (error);		devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);	if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) {		ahd->chip |= AHD_PCI;		/* Disable PCIX workarounds when running in PCI mode. */		ahd->bugs &= ~AHD_PCIX_BUG_MASK;	} else {		ahd->chip |= AHD_PCIX;	}	ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)];	ahd_power_state_change(ahd, AHD_POWER_STATE_D0);	error = ahd_pci_map_registers(ahd);	if (error != 0)		return (error);	/*	 * If we need to support high memory, enable dual	 * address cycles.  This bit must be set to enable	 * high address bit generation even if we are on a	 * 64bit bus (PCI64BIT set in devconfig).	 */	if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {		uint32_t devconfig;		if (bootverbose)			printf("%s: Enabling 39Bit Addressing\n",			       ahd_name(ahd));		devconfig = ahd_pci_read_config(ahd->dev_softc,						DEVCONFIG, /*bytes*/4);		devconfig |= DACEN;		ahd_pci_write_config(ahd->dev_softc, DEVCONFIG,				     devconfig, /*bytes*/4);	}		/* Ensure busmastering is enabled */	command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);	command |= PCIM_CMD_BUSMASTEREN;	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2);	error = ahd_softc_init(ahd);	if (error != 0)		return (error);	ahd->bus_intr = ahd_pci_intr;	error = ahd_reset(ahd, /*reinit*/FALSE);	if (error != 0)		return (ENXIO);	ahd->pci_cachesize =	    ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME,				/*bytes*/1) & CACHESIZE;	ahd->pci_cachesize *= 4;	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	/* See if we have a SEEPROM and perform auto-term */	error = ahd_check_extport(ahd);	if (error != 0)		return (error);	/* Core initialization */	error = ahd_init(ahd);	if (error != 0)		return (error);	/*	 * Allow interrupts now that we are completely setup.	 */	error = ahd_pci_map_int(ahd);	if (!error)		ahd->init_level++;	return error;}/* * Perform some simple tests that should catch situations where * our registers are invalidly mapped. */intahd_pci_test_register_access(struct ahd_softc *ahd){	uint32_t cmd;	u_int	 targpcistat;	u_int	 pci_status1;	int	 error;	uint8_t	 hcntrl;	error = EIO;	/*	 * Enable PCI error interrupt status, but suppress NMIs	 * generated by SERR raised due to target aborts.	 */	cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,			     cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2);	/*	 * First a simple test to see if any	 * registers can be read.  Reading	 * HCNTRL has no side effects and has	 * at least one bit that is guaranteed to	 * be zero so it is a good register to	 * use for this test.	 */	hcntrl = ahd_inb(ahd, HCNTRL);	if (hcntrl == 0xFF)		goto fail;	/*	 * Next create a situation where write combining	 * or read prefetching could be initiated by the	 * CPU or host bridge.  Our device does not support	 * either, so look for data corruption and/or flaged	 * PCI errors.  First pause without causing another	 * chip reset.	 */	hcntrl &= ~CHIPRST;	ahd_outb(ahd, HCNTRL, hcntrl|PAUSE);	while (ahd_is_paused(ahd) == 0)		;	/* Clear any PCI errors that occurred before our driver attached. */	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);	targpcistat = ahd_inb(ahd, TARGPCISTAT);	ahd_outb(ahd, TARGPCISTAT, targpcistat);	pci_status1 = ahd_pci_read_config(ahd->dev_softc,					  PCIR_STATUS + 1, /*bytes*/1);	ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,			     pci_status1, /*bytes*/1);	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	ahd_outb(ahd, CLRINT, CLRPCIINT);	ahd_outb(ahd, SEQCTL0, PERRORDIS);	ahd_outl(ahd, SRAM_BASE, 0x5aa555aa);	if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa)		goto fail;	if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) {		u_int targpcistat;		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);		targpcistat = ahd_inb(ahd, TARGPCISTAT);		if ((targpcistat & STA) != 0)			goto fail;	}	error = 0;fail:	if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) {		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);		targpcistat = ahd_inb(ahd, TARGPCISTAT);		/* Silently clear any latched errors. */		ahd_outb(ahd, TARGPCISTAT, targpcistat);		pci_status1 = ahd_pci_read_config(ahd->dev_softc,						  PCIR_STATUS + 1, /*bytes*/1);		ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,				     pci_status1, /*bytes*/1);		ahd_outb(ahd, CLRINT, CLRPCIINT);	}	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS);	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);	return (error);}/* * Check the external port logic for a serial eeprom * and termination/cable detection contrls. */static intahd_check_extport(struct ahd_softc *ahd){	struct	vpd_config vpd;	struct	seeprom_config *sc;	u_int	adapter_control;	int	have_seeprom;	int	error;	sc = ahd->seep_config;	have_seeprom = ahd_acquire_seeprom(ahd);	if (have_seeprom) {		u_int start_addr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -