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

📄 pci2220i.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/**************************************************************************** * Perceptive Solutions, Inc. PCI-2220I device driver for Linux. * * pci2220i.c - Linux Host Driver for PCI-2220I EIDE RAID Adapters * * Copyright (c) 1997-1999 Perceptive Solutions, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that redistributions of source * code retain the above copyright notice and this comment without * modification. * * Technical updates and product information at: *  http://www.psidisk.com * * Please send questions, comments, bug reports to: *  tech@psidisk.com Technical Support * * *	Revisions 1.10		Mar-26-1999 *		- Updated driver for RAID and hot reconstruct support. * *	Revisions 1.11		Mar-26-1999 *		- Fixed spinlock and PCI configuration. * *	Revision 2.00		December-1-1999 *		- Added code for the PCI-2240I controller *		- Added code for ATAPI devices. *		- Double buffer for scatter/gather support * *	Revision 2.10		March-27-2000 *		- Added support for dynamic DMA * ****************************************************************************///#define DEBUG 1#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/pci.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/kdev_t.h>#include <linux/blk.h>#include <linux/timer.h>#include <linux/spinlock.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include "scsi.h"#include "hosts.h"#include "pci2220i.h"#include "psi_dale.h"#define	PCI2220I_VERSION		"2.10"#define	READ_CMD				IDE_CMD_READ_MULTIPLE#define	WRITE_CMD				IDE_CMD_WRITE_MULTIPLE#define	MAX_BUS_MASTER_BLOCKS	SECTORSXFER		// This is the maximum we can bus master#ifdef DEBUG#define DEB(x) x#define STOP_HERE()	{int st;for(st=0;st<100;st++){st=1;}}#else#define DEB(x)#define STOP_HERE()#endif#define MAXADAPTER 4					// Increase this and the sizes of the arrays below, if you need more.typedef struct	{	UCHAR			byte6;				// device select register image	UCHAR			spigot;				// spigot number	UCHAR			spigots[2];			// RAID spigots	UCHAR			deviceID[2];		// device ID codes	USHORT			sectors;			// number of sectors per track	USHORT			heads;				// number of heads	USHORT			cylinders;			// number of cylinders for this device	USHORT			spareword;			// placeholder	ULONG			blocks;				// number of blocks on device	DISK_MIRROR		DiskMirror[2];		// RAID status and control	ULONG			lastsectorlba[2];	// last addressable sector on the drive	USHORT			raid;				// RAID active flag	USHORT			mirrorRecon;	UCHAR			reconOn;	USHORT			reconCount;	USHORT			reconIsStarting;	// indicate hot reconstruct is starting	UCHAR			cmdDrqInt;			// flag for command interrupt	UCHAR			packet;				// command packet size in bytes	}	OUR_DEVICE, *POUR_DEVICE;	typedef struct	{	USHORT		 bigD;					// identity is a PCI-2240I if true, otherwise a PCI-2220I	USHORT		 atapi;					// this interface is for ATAPI devices only	ULONG		 regDmaDesc;			// address of the DMA discriptor register for direction of transfer	ULONG		 regDmaCmdStat;			// Byte #1 of DMA command status register	ULONG		 regDmaAddrPci;			// 32 bit register for PCI address of DMA	ULONG		 regDmaAddrLoc;			// 32 bit register for local bus address of DMA	ULONG		 regDmaCount;			// 32 bit register for DMA transfer count	ULONG		 regDmaMode;			// 32 bit register for DMA mode control	ULONG		 regRemap;				// 32 bit local space remap	ULONG		 regDesc;				// 32 bit local region descriptor	ULONG		 regRange;				// 32 bit local range	ULONG		 regIrqControl;			// 16 bit Interrupt enable/disable and status	ULONG		 regScratchPad;			// scratch pad I/O base address	ULONG		 regBase;				// Base I/O register for data space	ULONG		 regData;				// data register I/O address	ULONG		 regError;				// error register I/O address	ULONG		 regSectCount;			// sector count register I/O address	ULONG		 regLba0;				// least significant byte of LBA	ULONG		 regLba8;				// next least significant byte of LBA	ULONG		 regLba16;				// next most significan byte of LBA	ULONG		 regLba24;				// head and most 4 significant bits of LBA	ULONG		 regStatCmd;			// status on read and command on write register	ULONG		 regStatSel;			// board status on read and spigot select on write register	ULONG		 regFail;				// fail bits control register	ULONG		 regAltStat;			// alternate status and drive control register	ULONG		 basePort;				// PLX base I/O port	USHORT		 timingMode;			// timing mode currently set for adapter	USHORT		 timingPIO;				// TRUE if PIO timing is active	struct pci_dev	*pcidev;	ULONG		 timingAddress;			// address to use on adapter for current timing mode	ULONG		 irqOwned;				// owned IRQ or zero if shared	UCHAR		 numberOfDrives;		// saved number of drives on this controller	UCHAR		 failRegister;			// current inverted data in fail register	OUR_DEVICE	 device[BIGD_MAXDRIVES];	DISK_MIRROR	*raidData[BIGD_MAXDRIVES];	ULONG		 startSector;	USHORT		 sectorCount;	ULONG		 readCount;	UCHAR		*currentSgBuffer;	ULONG		 currentSgCount;	USHORT		 nextSg;	UCHAR		 cmd;	Scsi_Cmnd	*SCpnt;	POUR_DEVICE	 pdev;					// current device opearating on	USHORT		 devInReconIndex;	USHORT		 expectingIRQ;	USHORT		 reconOn;				// Hot reconstruct is to be done.	USHORT		 reconPhase;			// Hot reconstruct operation is in progress.	ULONG		 reconSize;	USHORT		 demoFail;				// flag for RAID failure demonstration	USHORT		 survivor;	USHORT		 failinprog;	struct timer_list	reconTimer;		struct timer_list	timer;	UCHAR		*kBuffer;	dma_addr_t	 kBufferDma;	UCHAR		 reqSense;	UCHAR		 atapiCdb[16];	UCHAR		 atapiSpecial;	}	ADAPTER2220I, *PADAPTER2220I;#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)#define	RECON_PHASE_READY		0x01#define	RECON_PHASE_COPY		0x02#define	RECON_PHASE_UPDATE		0x03#define	RECON_PHASE_LAST		0x04#define	RECON_PHASE_END			0x07	#define	RECON_PHASE_MARKING		0x80#define	RECON_PHASE_FAILOVER	0xFFstatic struct	Scsi_Host 	   *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapterstatic			int				NumAdapters = 0;static			int				Installed = 0;static			SETUP			DaleSetup;static			DISK_MIRROR		DiskMirror[BIGD_MAXDRIVES];static			ULONG			ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE5};static			ULONG			ModeArray2[] = {BIGD_DATA_MODE2, BIGD_DATA_MODE3, BIGD_DATA_MODE4, BIGD_DATA_MODE5};static void ReconTimerExpiry (unsigned long data);/******************************************************************************************************* *	Name:			Alarm * *	Description:	Sound the for the given device * *	Parameters:		padapter - Pointer adapter data structure. *					device	 - Device number. *	 *	Returns:		Nothing. * ******************************************************************************************************/static void Alarm (PADAPTER2220I padapter, UCHAR device)	{	UCHAR	zc;	if ( padapter->bigD )		{		zc = device | (FAIL_ANY | FAIL_AUDIBLE);		if ( padapter->failRegister & FAIL_ANY ) 			zc |= FAIL_MULTIPLE;				padapter->failRegister = zc;		outb_p (~zc, padapter->regFail);		}	else		outb_p (0x3C | (1 << device), padapter->regFail);			// sound alarm and set fail light			}/**************************************************************** *	Name:	MuteAlarm	:LOCAL * *	Description:	Mute the audible alarm. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static void MuteAlarm (PADAPTER2220I padapter)	{	UCHAR	old;	if ( padapter->bigD )		{		padapter->failRegister &= ~FAIL_AUDIBLE;		outb_p (~padapter->failRegister, padapter->regFail);		}	else		{		old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);		outb_p (old | 0x40, padapter->regFail);		}	}/**************************************************************** *	Name:	WaitReady	:LOCAL * *	Description:	Wait for device ready. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static int WaitReady (PADAPTER2220I padapter)	{	ULONG	z;	UCHAR	status;	for ( z = 0;  z < (TIMEOUT_READY * 4);  z++ )		{		status = inb_p (padapter->regStatCmd);		if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )			return 0;		udelay (250);		}	return status;	}/**************************************************************** *	Name:	WaitReadyReset	:LOCAL * *	Description:	Wait for device ready. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static int WaitReadyReset (PADAPTER2220I padapter)	{	ULONG	z;	UCHAR	status;	for ( z = 0;  z < (125 * 16);  z++ )				// wait up to 1/4 second		{		status = inb_p (padapter->regStatCmd);		if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )			{			DEB (printk ("\nPCI2220I:  Reset took %ld mSec to be ready", z / 8));			return 0;			}		udelay (125);		}	DEB (printk ("\nPCI2220I:  Reset took more than 2 Seconds to come ready, Disk Failure"));	return status;	}/**************************************************************** *	Name:	WaitDrq	:LOCAL * *	Description:	Wait for device ready for data transfer. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static int WaitDrq (PADAPTER2220I padapter)	{	ULONG	z;	UCHAR	status;	for ( z = 0;  z < (TIMEOUT_DRQ * 4);  z++ )		{		status = inb_p (padapter->regStatCmd);		if ( status & IDE_STATUS_DRQ )			return 0;		udelay (250);		}	return status;	}/**************************************************************** *	Name:	AtapiWaitReady	:LOCAL * *	Description:	Wait for device busy and DRQ to be cleared. * *	Parameters:		padapter - Pointer adapter data structure. *					msec	 - Number of milliseconds to wait. * *	Returns:		TRUE if drive does not clear busy in time. * ****************************************************************/static int AtapiWaitReady (PADAPTER2220I padapter, int msec)	{	int z;	for ( z = 0;  z < (msec * 16);  z++ )		{		if ( !(inb_p (padapter->regStatCmd) & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) )			return FALSE;		udelay (125);		}	return TRUE;	}/**************************************************************** *	Name:	AtapiWaitDrq	:LOCAL * *	Description:	Wait for device ready for data transfer. * *	Parameters:		padapter - Pointer adapter data structure. *					msec	 - Number of milliseconds to wait. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static int AtapiWaitDrq (PADAPTER2220I padapter, int msec)	{	ULONG	z;	for ( z = 0;  z < (msec * 16);  z++ )		{		if ( inb_p (padapter->regStatCmd) & IDE_STATUS_DRQ )			return 0;		udelay (128);		}	return TRUE;	}/**************************************************************** *	Name:	HardReset	:LOCAL * *	Description:	Wait for device ready for data transfer. * *	Parameters:		padapter - Pointer adapter data structure. *					pdev	 - Pointer to device. *					spigot	 - Spigot number. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)	{	DEB (printk ("\npci2220i:RESET  spigot = %X  devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1]));	mdelay (100);										// just wait 100 mSec to let drives flush		SelectSpigot (padapter, spigot | SEL_IRQ_OFF);		outb_p (0x0E, padapter->regAltStat);					// reset the suvivor	udelay (100);											// wait a little		outb_p (0x08, padapter->regAltStat);					// clear the reset	udelay (100);	outb_p (0xA0, padapter->regLba24);						// select the master drive	if ( WaitReadyReset (padapter) )		{		DEB (printk ("\npci2220i: master not ready after reset"));		return TRUE;		}	outb_p (0xB0, padapter->regLba24);						// try the slave drive	if ( (inb_p (padapter->regStatCmd) & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) 		{		DEB (printk ("\nPCI2220I: initializing slave drive on spigot %X", spigot));		outb_p (SECTORSXFER, padapter->regSectCount);		WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);			if ( WaitReady (padapter) )			{			DEB (printk ("\npci2220i: slave not ready after set multiple"));			return TRUE;			}		}		outb_p (0xA0, padapter->regLba24);				// select the drive	outb_p (SECTORSXFER, padapter->regSectCount);	WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);		if ( WaitReady (padapter) )		{		DEB (printk ("\npci2220i: master not ready after set multiple"));		return TRUE;		}	return FALSE;	}/**************************************************************** *	Name:	AtapiReset	:LOCAL * *	Description:	Wait for device ready for data transfer. * *	Parameters:		padapter - Pointer adapter data structure. *					pdev	 - Pointer to device. * *	Returns:		TRUE if drive does not come ready. * ****************************************************************/static int AtapiReset (PADAPTER2220I padapter, POUR_DEVICE pdev)	{	SelectSpigot (padapter, pdev->spigot);	AtapiDevice (padapter, pdev->byte6);	AtapiCountLo (padapter, 0);	AtapiCountHi (padapter, 0);	WriteCommand (padapter, IDE_COMMAND_ATAPI_RESET);

⌨️ 快捷键说明

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