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

📄 eata_dma.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 4 页
字号:
/************************************************************ *							    * *		    Linux EATA SCSI driver		    * *							    * *  based on the CAM document CAM/89-004 rev. 2.0c,	    * *  DPT's driver kit, some internal documents and source,   * *  and several other Linux scsi drivers and kernel docs.   * *							    * *  The driver currently:				    * *	-supports all ISA based EATA-DMA boards		    * *       like PM2011, PM2021, PM2041, PM3021                * *	-supports all EISA based EATA-DMA boards	    * *       like PM2012B, PM2022, PM2122, PM2322, PM2042,      * *            PM3122, PM3222, PM3332                        * *	-supports all PCI based EATA-DMA boards		    * *       like PM2024, PM2124, PM2044, PM2144, PM3224,       * *            PM3334                                        * *      -supports the Wide, Ultra Wide and Differential     * *       versions of the boards                             * *	-supports multiple HBAs with & without IRQ sharing  * *	-supports all SCSI channels on multi channel boards * *      -supports ix86 and MIPS, untested on ALPHA          * *	-needs identical IDs on all channels of a HBA	    *  *	-can be loaded as module			    * *	-displays statistical and hardware information	    * *	 in /proc/scsi/eata_dma				    * *      -provides rudimentary latency measurement           *  *       possibilities via /proc/scsi/eata_dma/<hostnum>    * *							    * *  (c)1993-96 Michael Neuffer			            * *             mike@i-Connect.Net                           * *	       neuffer@mail.uni-mainz.de	            * *							    * *  This program is free software; you can redistribute it  * *  and/or modify it under the terms of the GNU General	    * *  Public License as published by the Free Software	    * *  Foundation; either version 2 of the License, or	    * *  (at your option) any later version.			    * *							    * *  This program is distributed in the hope that it will be * *  useful, but WITHOUT ANY WARRANTY; without even the	    * *  implied warranty of MERCHANTABILITY or FITNESS FOR A    * *  PARTICULAR PURPOSE.	 See the GNU General Public License * *  for more details.					    * *							    * *  You should have received a copy of the GNU General	    * *  Public License along with this kernel; if not, write to * *  the Free Software Foundation, Inc., 675 Mass Ave,	    * *  Cambridge, MA 02139, USA.				    * *							    * * I have to thank DPT for their excellent support. I took  * * me almost a year and a stopover at their HQ, on my first * * trip to the USA, to get it, but since then they've been  * * very helpful and tried to give me all the infos and	    * * support I need.					    * *							    * * Thanks also to Simon Shapiro, Greg Hosler and Mike       * * Jagdis who did a lot of testing and found quite a number * * of bugs during the development.                          * ************************************************************ *  last change: 96/10/21                 OS: Linux 2.0.23  * ************************************************************//* Look in eata_dma.h for configuration and revision information */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/in.h>#include <linux/bios32.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <asm/types.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/pgtable.h>#ifdef __mips__#include <asm/cachectl.h>#endif#include <linux/blk.h>#include "scsi.h"#include "sd.h"#include "hosts.h"#include "eata_dma.h"#include "eata_dma_proc.h" #include <linux/stat.h>#include <linux/config.h>	/* for CONFIG_PCI */struct proc_dir_entry proc_scsi_eata_dma = {    PROC_SCSI_EATA, 8, "eata_dma",    S_IFDIR | S_IRUGO | S_IXUGO, 2};static u32 ISAbases[] ={0x1F0, 0x170, 0x330, 0x230};static unchar EISAbases[] ={1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};static uint registered_HBAs = 0;static struct Scsi_Host *last_HBA = NULL;static struct Scsi_Host *first_HBA = NULL;static unchar reg_IRQ[] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};static unchar reg_IRQL[] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};static struct eata_sp *status = 0;   /* Statuspacket array   */static void *dma_scratch = 0;static struct eata_register *fake_int_base;static int fake_int_result;static int fake_int_happened;static ulong int_counter = 0;static ulong queue_counter = 0;void eata_scsi_done (Scsi_Cmnd * scmd){    scmd->request.rq_status = RQ_SCSI_DONE;    if (scmd->request.sem != NULL)	up(scmd->request.sem);        return;}   void eata_fake_int_handler(s32 irq, void *dev_id, struct pt_regs * regs){    fake_int_result = inb((ulong)fake_int_base + HA_RSTATUS);    fake_int_happened = TRUE;    DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%d base %p"			  " res %#x\n", irq, fake_int_base, fake_int_result));    return;}#include "eata_dma_proc.c"#ifdef MODULEint eata_release(struct Scsi_Host *sh){    uint i;    if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq, NULL);    else reg_IRQ[sh->irq]--;        scsi_init_free((void *)status, 512);    scsi_init_free((void *)dma_scratch - 4, 1024);    for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */	if(SD(sh)->ccb[i].sg_list != NULL)	    scsi_init_free((void *) SD(sh)->ccb[i].sg_list, 			   sh->sg_tablesize * sizeof(struct eata_sg_list));    }        if (SD(sh)->channel == 0) {	if (sh->dma_channel != BUSMASTER) free_dma(sh->dma_channel);	if (sh->io_port && sh->n_io_port)	    release_region(sh->io_port, sh->n_io_port);    }    return(TRUE);}#endifinline void eata_latency_in(struct eata_ccb *cp, hostdata *hd){    uint time;    time = jiffies - cp->timestamp;    if(hd->all_lat[1] > time)        hd->all_lat[1] = time;    if(hd->all_lat[2] < time)        hd->all_lat[2] = time;    hd->all_lat[3] += time;    hd->all_lat[0]++;    if((cp->rw_latency) == WRITE) { /* was WRITE */        if(hd->writes_lat[cp->sizeindex][1] > time)	    hd->writes_lat[cp->sizeindex][1] = time;	if(hd->writes_lat[cp->sizeindex][2] < time)	    hd->writes_lat[cp->sizeindex][2] = time;	hd->writes_lat[cp->sizeindex][3] += time;	hd->writes_lat[cp->sizeindex][0]++;    } else if((cp->rw_latency) == READ) {        if(hd->reads_lat[cp->sizeindex][1] > time)	    hd->reads_lat[cp->sizeindex][1] = time;	if(hd->reads_lat[cp->sizeindex][2] < time)	    hd->reads_lat[cp->sizeindex][2] = time;	hd->reads_lat[cp->sizeindex][3] += time;	hd->reads_lat[cp->sizeindex][0]++;    }} inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd){    int x, z;    short *sho;    long *lon;    x = 0;	                        /* just to keep GCC quiet */     cp->timestamp = jiffies;	        /* For latency measurements */    switch(cmd->cmnd[0]) {    case WRITE_6:           x = cmd->cmnd[4]/2; 	cp->rw_latency = WRITE;	break;    case READ_6:            x = cmd->cmnd[4]/2; 	cp->rw_latency = READ;	break;    case WRITE_10:           sho = (short *) &cmd->cmnd[7];	x = ntohs(*sho)/2;	      	cp->rw_latency = WRITE;	break;    case READ_10:        sho = (short *) &cmd->cmnd[7];	x = ntohs(*sho)/2;	      	cp->rw_latency = READ;	break;    case WRITE_12:           lon = (long *) &cmd->cmnd[6];	x = ntohl(*lon)/2;	      	cp->rw_latency = WRITE;	break;    case READ_12:        lon = (long *) &cmd->cmnd[6];	x = ntohl(*lon)/2;	      	cp->rw_latency = READ;	break;    default:        cp->rw_latency = OTHER;	break;    }    if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || 	cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 || 	cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) {        for(z = 0; (x > (1 << z)) && (z <= 11); z++) 	    /* nothing */;	cp->sizeindex = z;    } }void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs){    uint i, result = 0;    uint hba_stat, scsi_stat, eata_stat;    Scsi_Cmnd *cmd;    struct eata_ccb *ccb;    struct eata_sp *sp;    uint base;    uint x;    struct Scsi_Host *sh;    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {	if (sh->irq != irq)	    continue;		while(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {	    	    int_counter++;	    	    sp = &SD(sh)->sp;#ifdef __mips__            sys_cacheflush(sp, sizeof(struct eata_sp), 2);#endif	    ccb = sp->ccb;	    	    if(ccb == NULL) {		eata_stat = inb((uint)sh->base + HA_RSTATUS);		printk("eata_dma: int_handler, Spurious IRQ %d "		       "received. CCB pointer not set.\n", irq);		break;	    }	    cmd = ccb->cmd;	    base = (uint) cmd->host->base;       	    hba_stat = sp->hba_stat;	    	    scsi_stat = (sp->scsi_stat >> 1) & 0x1f; 	    	    if (sp->EOC == FALSE) {		eata_stat = inb(base + HA_RSTATUS);		printk(KERN_WARNING "eata_dma: int_handler, board: %x cmd %lx "		       "returned unfinished.\n"		       "EATA: %x HBA: %x SCSI: %x spadr %lx spadrirq %lx, "		       "irq%d\n", base, (long)ccb, eata_stat, hba_stat, 		       scsi_stat,(long)&status, (long)&status[irq], irq);		cmd->result = DID_ERROR << 16;		ccb->status = FREE;		cmd->scsi_done(cmd);		break;	    } 	               sp->EOC = FALSE; /* Clean out this flag */           if (ccb->status == LOCKED || ccb->status == RESET) {               printk("eata_dma: int_handler, reseted command pid %ld returned"		      "\n", cmd->pid);	       DBG(DBG_INTR && DBG_DELAY, DELAY(1));	    }	    	    eata_stat = inb(base + HA_RSTATUS); 	    DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, "				 "target: %x, lun: %x, ea_s: %#.2x, hba_s: "				 "%#.2x \n", irq, base, cmd->pid, cmd->target,				 cmd->lun, eata_stat, hba_stat));	    	    switch (hba_stat) {	    case HA_NO_ERROR:	/* NO Error */		if(HD(cmd)->do_latency == TRUE && ccb->timestamp) 		    eata_latency_in(ccb, HD(cmd));		result = DID_OK << 16;		break;	    case HA_ERR_SEL_TO:	        /* Selection Timeout */	    case HA_ERR_CMD_TO:	        /* Command Timeout   */		result = DID_TIME_OUT << 16;		break;	    case HA_BUS_RESET:		/* SCSI Bus Reset Received */		result = DID_RESET << 16;		DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: BUS RESET "				       "received on cmd %ld\n", 				       HD(cmd)->HBA_number, cmd->pid));		break;	    case HA_INIT_POWERUP:	/* Initial Controller Power-up */		if (cmd->device->type != TYPE_TAPE)		    result = DID_BUS_BUSY << 16;		else		    result = DID_ERROR << 16;				for (i = 0; i < MAXTARGET; i++)		DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld "				       "returned with INIT_POWERUP\n", 				       HD(cmd)->HBA_number, cmd->pid));		break;	    case HA_CP_ABORT_NA:	    case HA_CP_ABORTED:		result = DID_ABORT << 16;		DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: aborted cmd "				       "returned\n", HD(cmd)->HBA_number)); 		break;	    case HA_CP_RESET_NA:	    case HA_CP_RESET:	        HD(cmd)->resetlevel[cmd->channel] = 0; 		result = DID_RESET << 16;		DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd "				       "pid %ldreturned\n", 				       HD(cmd)->HBA_number, cmd->pid));	    case HA_SCSI_HUNG:	        /* SCSI Hung                 */	        printk(KERN_ERR "scsi%d: SCSI hung\n", HD(cmd)->HBA_number);		result = DID_ERROR << 16;		break;	    case HA_RSENSE_FAIL:        /* Auto Request-Sense Failed */	        DBG(DBG_STATUS, printk(KERN_ERR "scsi%d: Auto Request Sense "				       "Failed\n", HD(cmd)->HBA_number));		result = DID_ERROR << 16;		break;	    case HA_UNX_BUSPHASE:	/* Unexpected Bus Phase */	    case HA_UNX_BUS_FREE:	/* Unexpected Bus Free */	    case HA_BUS_PARITY:	        /* Bus Parity Error */	    case HA_UNX_MSGRJCT:	/* Unexpected Message Reject */	    case HA_RESET_STUCK:        /* SCSI Bus Reset Stuck */	    case HA_PARITY_ERR:	        /* Controller Ram Parity */	    default:		result = DID_ERROR << 16;		break;	    }	    cmd->result = result | (scsi_stat << 1); 	    #if DBG_INTR2	    if (scsi_stat || result || hba_stat || eata_stat != 0x50 		|| cmd->scsi_done == NULL || cmd->device->id == 7) 		printk("HBA: %d, channel %d, id: %d, lun %d, pid %ld:\n" 		       "eata_stat %#x, hba_stat %#.2x, scsi_stat %#.2x, "		       "sense_key: %#x, result: %#.8x\n", x, 		       cmd->device->channel, cmd->device->id, cmd->device->lun,		       cmd->pid, eata_stat, hba_stat, scsi_stat, 		       cmd->sense_buffer[2] & 0xf, cmd->result); 	    DBG(DBG_INTR&&DBG_DELAY,DELAY(1));#endif	    	    ccb->status = FREE;	    /* now we can release the slot  */	    cmd->scsi_done(cmd);	}    }    return;}inline int eata_send_command(u32 addr, u32 base, u8 command){    long loop = R_LIMIT;        while (inb(base + HA_RAUXSTAT) & HA_ABUSY)	if (--loop == 0)	    return(FALSE);    if(addr != (u32) NULL)        addr = virt_to_bus((void *)addr);    /*

⌨️ 快捷键说明

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