📄 pci2220i.c
字号:
/**************************************************************************** * 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 + -