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

📄 pci2000.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/**************************************************************************** * Perceptive Solutions, Inc. PCI-2000 device driver for Linux. * * pci2000.c - Linux Host Driver for PCI-2000 IntelliCache SCSI 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	Jan-21-1999 *		- Fixed sign on message to reflect proper controller name. *		- Added support for RAID status monitoring and control. * *  Revisions	1.11	Mar-22-1999 *		- Fixed control timeout to not lock up the entire system if *		  controller goes offline completely. * *	Revisions 1.12		Mar-26-1999 *		- Fixed spinlock and PCI configuration. * *	Revisions 1.20		Mar-27-2000 *		- Added support for dynamic DMA * ****************************************************************************/#define PCI2000_VERSION		"1.20"#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/string.h>#include <linux/pci.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include <linux/stat.h>#include <linux/spinlock.h>#include "pci2000.h"#include "psi_roy.h"//#define DEBUG 1#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#endiftypedef struct	{	unsigned int	address;	unsigned int	length;	}	SCATGATH, *PSCATGATH;typedef struct	{	Scsi_Cmnd		*SCpnt;	PSCATGATH		 scatGath;	dma_addr_t		 scatGathDma;	UCHAR			*cdb;	dma_addr_t		 cdbDma; 	UCHAR			 tag;	}	DEV2000, *PDEV2000;typedef struct	{	ULONG			 basePort;	ULONG			 mb0;	ULONG			 mb1;	ULONG			 mb2;	ULONG			 mb3;	ULONG			 mb4;	ULONG			 cmd;	ULONG			 tag;	ULONG			 irqOwned;	struct pci_dev	*pdev;	DEV2000	 		 dev[MAX_BUS][MAX_UNITS];	}	ADAPTER2000, *PADAPTER2000;#define HOSTDATA(host) ((PADAPTER2000)&host->hostdata)#define consistentLen (MAX_BUS * MAX_UNITS * (16 * sizeof (SCATGATH) + MAX_COMMAND_SIZE))static struct	Scsi_Host 	   *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapterstatic			int				NumAdapters = 0;/**************************************************************** *	Name:			WaitReady	:LOCAL * *	Description:	Wait for controller ready. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE on not ready. * ****************************************************************/static int WaitReady (PADAPTER2000 padapter)	{	ULONG	z;	for ( z = 0;  z < (TIMEOUT_COMMAND * 4);  z++ )		{		if ( !inb_p (padapter->cmd) )			return FALSE;		udelay (250);		};									return TRUE;	}/**************************************************************** *	Name:			WaitReadyLong	:LOCAL * *	Description:	Wait for controller ready. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE on not ready. * ****************************************************************/static int WaitReadyLong (PADAPTER2000 padapter)	{	ULONG	z;	for ( z = 0;  z < (5000 * 4);  z++ )		{		if ( !inb_p (padapter->cmd) )			return FALSE;		udelay (250);		};									return TRUE;	}/**************************************************************** *	Name:	OpDone	:LOCAL * *	Description:	Clean up operation and issue done to caller. * *	Parameters:		SCpnt	- Pointer to SCSI command structure. *					status	- Caller status. * *	Returns:		Nothing. * ****************************************************************/static void OpDone (Scsi_Cmnd *SCpnt, ULONG status)	{	SCpnt->result = status;	SCpnt->scsi_done (SCpnt);	}/**************************************************************** *	Name:	Command		:LOCAL * *	Description:	Issue queued command to the PCI-2000. * *	Parameters:		padapter - Pointer to adapter information structure. *					cmd		 - PCI-2000 command byte. * *	Returns:		Non-zero command tag if operation is accepted. * ****************************************************************/static UCHAR Command (PADAPTER2000 padapter, UCHAR cmd)	{	outb_p (cmd, padapter->cmd);	if ( WaitReady (padapter) )		return 0;	if ( inw_p (padapter->mb0) )		return 0;	return inb_p (padapter->mb1);	}/**************************************************************** *	Name:	BuildSgList		:LOCAL * *	Description:	Build the scatter gather list for controller. * *	Parameters:		SCpnt	 - Pointer to SCSI command structure. *					padapter - Pointer to adapter information structure. *					pdev	 - Pointer to adapter device structure. * *	Returns:		Non-zero in not scatter gather. * ****************************************************************/static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev)	{	int					 z;	int					 zc;	struct scatterlist	*sg;	if ( SCpnt->use_sg )		{		sg = (struct scatterlist *)SCpnt->request_buffer;		zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));		for ( z = 0;  z < zc;  z++ )			{			pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg));			pdev->scatGath[z].length = cpu_to_le32 (sg_dma_len (sg++));			}		outl (pdev->scatGathDma, padapter->mb2);		outl ((zc << 24) | SCpnt->request_bufflen, padapter->mb3);		return FALSE;		}	if ( !SCpnt->request_bufflen)		{		outl (0, padapter->mb2);		outl (0, padapter->mb3);		return TRUE;		}	SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));	outl (SCpnt->SCp.have_data_in, padapter->mb2);	outl (SCpnt->request_bufflen, padapter->mb3);	return TRUE;	}/********************************************************************* *	Name:	PsiRaidCmd * *	Description:	Execute a simple command. * *	Parameters:		padapter - Pointer to adapter control structure. *					cmd		 - Roy command byte. * *	Returns:		Return error status. * ********************************************************************/static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)	{	if ( WaitReady (padapter) )						// test for command register ready		return DID_TIME_OUT;	outb_p (cmd, padapter->cmd);					// issue command	if ( WaitReadyLong (padapter) )					// wait for adapter ready		return DID_TIME_OUT;	return DID_OK;	}/**************************************************************** *	Name:	Irq_Handler	:LOCAL * *	Description:	Interrupt handler. * *	Parameters:		irq		- Hardware IRQ number. *					dev_id	- *					regs	- * *	Returns:		TRUE if drive is not ready in time. * ****************************************************************/static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)	{	struct Scsi_Host   *shost = NULL;	// Pointer to host data block	PADAPTER2000		padapter;		// Pointer to adapter control structure	PDEV2000			pdev;	Scsi_Cmnd		   *SCpnt;	UCHAR				tag = 0;	UCHAR				tag0;	ULONG				error;	int					pun;	int					bus;	int					z;    unsigned long		flags;    /*     * Disable interrupts, if they aren't already disabled and acquire     * the I/O spinlock.     */    spin_lock_irqsave (&io_request_lock, flags);	DEB(printk ("\npci2000 received interrupt "));	for ( z = 0; z < NumAdapters;  z++ )										// scan for interrupt to process		{		if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )			{			tag = inb_p (HOSTDATA(PsiHost[z])->tag);			if (  tag )				{				shost = PsiHost[z];				break;				}			}		}	if ( !shost )		{		DEB (printk ("\npci2000: not my interrupt"));		goto irq_return;		}	padapter = HOSTDATA(shost);	tag0 = tag & 0x7F;															// mask off the error bit	for ( bus = 0;  bus < MAX_BUS;  bus++ )										// scan the busses    	{		for ( pun = 0;  pun < MAX_UNITS;  pun++ )								// scan the targets    		{			pdev = &padapter->dev[bus][pun];			if ( !pdev->tag )    			continue;			if ( pdev->tag == tag0 )											// is this it?				{				pdev->tag = 0;				SCpnt = pdev->SCpnt;				goto unmapProceed;    			}			}    	}	outb_p (0xFF, padapter->tag);												// clear the op interrupt	outb_p (CMD_DONE, padapter->cmd);											// complete the op	goto irq_return;;															// done, but, with what?unmapProceed:;	if ( !bus )		{		switch ( SCpnt->cmnd[0] )			{			case SCSIOP_TEST_UNIT_READY:				pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE);				goto irqProceed;			case SCSIOP_READ_CAPACITY:				pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, 8, PCI_DMA_FROMDEVICE);				goto irqProceed;			case SCSIOP_VERIFY:			case SCSIOP_START_STOP_UNIT:			case SCSIOP_MEDIUM_REMOVAL:				goto irqProceed;			}		}	if ( SCpnt->SCp.have_data_in )		pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));	else 		{		if ( SCpnt->use_sg )			pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));		}irqProceed:;	if ( tag & ERR08_TAGGED )												// is there an error here?		{		if ( WaitReady (padapter) )			{			OpDone (SCpnt, DID_TIME_OUT << 16);			goto irq_return;;			}		outb_p (tag0, padapter->mb0);										// get real error code		outb_p (CMD_ERROR, padapter->cmd);		if ( WaitReady (padapter) )											// wait for controller to suck up the op			{			OpDone (SCpnt, DID_TIME_OUT << 16);			goto irq_return;;			}		error = inl (padapter->mb0);										// get error data		outb_p (0xFF, padapter->tag);										// clear the op interrupt		outb_p (CMD_DONE, padapter->cmd);									// complete the op		DEB (printk ("status: %lX ", error));		if ( error == 0x00020002 )											// is this error a check condition?			{			if ( bus )														// are we doint SCSI commands?				{				OpDone (SCpnt, (DID_OK << 16) | 2);				goto irq_return;;				}			if ( *SCpnt->cmnd == SCSIOP_TEST_UNIT_READY )				OpDone (SCpnt, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2);	// test caller we have sense data too			else				OpDone (SCpnt, DID_ERROR << 16);			goto irq_return;;			}		OpDone (SCpnt, DID_ERROR << 16);		goto irq_return;;		}	outb_p (0xFF, padapter->tag);											// clear the op interrupt	outb_p (CMD_DONE, padapter->cmd);										// complete the op	OpDone (SCpnt, DID_OK << 16);irq_return:;    /*     * Release the I/O spinlock and restore the original flags     * which will enable interrupts if and only if they were     * enabled on entry.     */    spin_unlock_irqrestore (&io_request_lock, flags);	}/**************************************************************** *	Name:	Pci2000_QueueCommand * *	Description:	Process a queued command from the SCSI manager. * *	Parameters:		SCpnt - Pointer to SCSI command structure. *					done  - Pointer to done function to call. * *	Returns:		Status code. * ****************************************************************/int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))	{	UCHAR		   *cdb = (UCHAR *)SCpnt->cmnd;					// Pointer to SCSI CDB	PADAPTER2000	padapter = HOSTDATA(SCpnt->host);			// Pointer to adapter control structure	int				rc		 = -1;								// command return code	UCHAR			bus		 = SCpnt->channel;	UCHAR			pun		 = SCpnt->target;	UCHAR			lun		 = SCpnt->lun;	UCHAR			cmd;	PDEV2000		pdev	 = &padapter->dev[bus][pun];	if ( !done )		{		printk("pci2000_queuecommand: %02X: done can't be NULL\n", *cdb);		return 0;		}	SCpnt->scsi_done = done;	SCpnt->SCp.have_data_in = 0;

⌨️ 快捷键说明

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