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

📄 eata_pio.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 2 页
字号:
/************************************************************ *                                                          * *               Linux EATA SCSI PIO 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 EATA-PIO boards                       * *      -only supports DASD devices                         * *                                                          * *  (c)1993-96 Michael Neuffer, Alfred Arnold               * *             neuffer@goofy.zdv.uni-mainz.de               * *             a.arnold@kfa-juelich.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.                               * *                                                          * ************************************************************ *  last change: 96/07/16                  OS: Linux 2.0.8  * ************************************************************//* Look in eata_pio.h for configuration 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 <asm/io.h>#include "eata_pio.h"#include "eata_dma_proc.h"#include "scsi.h"#include "sd.h"#include <linux/stat.h>#include <linux/config.h>	/* for CONFIG_PCI */struct proc_dir_entry proc_scsi_eata_pio = {    PROC_SCSI_EATA_PIO, 9, "eata_pio",    S_IFDIR | S_IRUGO | S_IXUGO, 2};static uint ISAbases[MAXISA] ={0x1F0, 0x170, 0x330, 0x230};static uint ISAirqs[MAXISA] ={14,12,15,11};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 ulong int_counter = 0;static ulong queue_counter = 0;#include "eata_pio_proc.c" #ifdef MODULEint eata_pio_release(struct Scsi_Host *sh){    if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq, NULL);    else reg_IRQ[sh->irq]--;    if (SD(sh)->channel == 0) {	if (sh->io_port && sh->n_io_port)	    release_region(sh->io_port, sh->n_io_port);    }    return(TRUE);}#endifvoid IncStat(Scsi_Pointer *SCp, uint Increment){    SCp->ptr+=Increment;     if ((SCp->this_residual-=Increment)==0)    {	if ((--SCp->buffers_residual)==0) SCp->Status=FALSE;	else	{	    SCp->buffer++;	    SCp->ptr=SCp->buffer->address;	    SCp->this_residual=SCp->buffer->length;	}    }}void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs){    uint eata_stat = 0xfffff;    Scsi_Cmnd *cmd;    hostdata *hd;    struct eata_ccb *cp;    uint base;    ulong flags;    uint x,z;    struct Scsi_Host *sh;    ushort zwickel=0;    unchar stat,odd;        save_flags(flags);    cli();        for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {	if (sh->irq != irq)	    continue;	if (inb((uint)sh->base + HA_RSTATUS) & HA_SBUSY)	    continue;		int_counter++;		hd=SD(sh);		cp = &hd->ccb[0];	cmd = cp->cmd;	base = (uint) cmd->host->base;		do	{	    stat=inb(base+HA_RSTATUS);	    if (stat&HA_SDRQ)		if (cp->DataIn)		{		    z=256; odd=FALSE;		    while ((cmd->SCp.Status)&&((z>0)||(odd)))		    {			if (odd) 			{ 			    *(cmd->SCp.ptr)=zwickel>>8; 			    IncStat(&cmd->SCp,1);			    odd=FALSE;			}			x=min(z,cmd->SCp.this_residual/2);			insw(base+HA_RDATA,cmd->SCp.ptr,x);			z-=x; 			IncStat(&cmd->SCp,2*x);			if ((z>0)&&(cmd->SCp.this_residual==1))			{			    zwickel=inw(base+HA_RDATA); 			    *(cmd->SCp.ptr)=zwickel&0xff;			    IncStat(&cmd->SCp,1); z--; 			    odd=TRUE;			}		    }		    while (z>0) {			zwickel=inw(base+HA_RDATA); 			z--;		    } 		}		else /* cp->DataOut */		{		    odd=FALSE; z=256;		    while ((cmd->SCp.Status)&&((z>0)||(odd)))		    {			if (odd)			{			    zwickel+=*(cmd->SCp.ptr)<<8; 			    IncStat(&cmd->SCp,1);			    outw(zwickel,base+HA_RDATA); 			    z--; 			    odd=FALSE; 			}			x=min(z,cmd->SCp.this_residual/2);			outsw(base+HA_RDATA,cmd->SCp.ptr,x);			z-=x; 			IncStat(&cmd->SCp,2*x);			if ((z>0)&&(cmd->SCp.this_residual==1))			{			    zwickel=*(cmd->SCp.ptr); 			    zwickel&=0xff;			    IncStat(&cmd->SCp,1); 			    odd=TRUE;			}  		    }		    while (z>0||odd) {			outw(zwickel,base+HA_RDATA); 			z--; 			odd=FALSE;		    }		}	}	while ((stat&HA_SDRQ)||((stat&HA_SMORE)&&hd->moresupport));		/* terminate handler if HBA goes busy again, i.e. transfers	 * more data */		if (stat&HA_SBUSY) break;		/* OK, this is quite stupid, but I haven't found any correct	 * way to get HBA&SCSI status so far */		if (!(inb(base+HA_RSTATUS)&HA_SERROR))	{	    cmd->result=(DID_OK<<16); 	    hd->devflags|=(1<<cp->cp_id);	}	else if (hd->devflags&1<<cp->cp_id) 	    cmd->result=(DID_OK<<16)+0x02;	else cmd->result=(DID_NO_CONNECT<<16);		if (cp->status == LOCKED) {	    cp->status = FREE;	    eata_stat = inb(base + HA_RSTATUS);	    printk(KERN_NOTICE "eata_pio: int_handler, freeing locked "                   "queueslot\n");	    DBG(DBG_INTR&&DBG_DELAY,DELAY(1));	    restore_flags(flags);	    return;	}	#if DBG_INTR2	if (stat != 0x50) 	    printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat,                    cmd->result); 	DBG(DBG_INTR&&DBG_DELAY,DELAY(1));#endif		cp->status = FREE;   /* now we can release the slot  */		restore_flags(flags);	cmd->scsi_done(cmd);	save_flags(flags);	cli();    }    restore_flags(flags);        return;}inline uint eata_pio_send_command(uint base, unchar command){    uint loop = HZ/2;        while (inb(base + HA_RSTATUS) & HA_SBUSY)	if (--loop == 0)	    return(TRUE);    /* Enable interrupts for HBA.  It is not the best way to do it at this     * place, but I hope that it doesn't interfere with the IDE driver      * initialization this way */    outb(HA_CTRL_8HEADS,base+HA_CTRLREG);        outb(command, base + HA_WCOMMAND);    return(FALSE);}int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){    uint x, y;    long flags;    uint base;        hostdata *hd;    struct Scsi_Host *sh;    struct eata_ccb *cp;        save_flags(flags);    cli();        queue_counter++;        hd = HD(cmd);    sh = cmd->host;    base = (uint) sh->base;        /* use only slot 0, as 2001 can handle only one cmd at a time */        y = x = 0;        if (hd->ccb[y].status!=FREE) { 		DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n",                              sh->can_queue,x,y));#if DEBUG_EATA	panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld "              "intrno: %ld\n", queue_counter, int_counter);#else	panic(KERN_EMERG "eata_pio: run out of queue slots....\n");#endif    }        cp = &hd->ccb[y];        memset(cp, 0, sizeof(struct eata_ccb));    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));	    cp->status = USED;      /* claim free slot */    DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:"                          " %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y));    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));        cmd->scsi_done = (void *)done;        switch (cmd->cmnd[0]) {    case CHANGE_DEFINITION: case COMPARE:         case COPY:    case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:    case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:    case FORMAT_UNIT:       case REASSIGN_BLOCKS: case RESERVE:    case SEARCH_EQUAL:      case SEARCH_HIGH:     case SEARCH_LOW:    case WRITE_6:           case WRITE_10:        case WRITE_VERIFY:    case UPDATE_BLOCK:      case WRITE_LONG:      case WRITE_SAME:          case SEARCH_HIGH_12:    case SEARCH_EQUAL_12: case SEARCH_LOW_12:    case WRITE_12:          case WRITE_VERIFY_12: case SET_WINDOW:     case MEDIUM_SCAN:       case SEND_VOLUME_TAG:                case 0xea:      /* alternate number for WRITE LONG */	cp->DataOut = TRUE; /* Output mode */	break;    case TEST_UNIT_READY:    default:	cp->DataIn = TRUE;  /* Input mode  */    }        cp->Interpret = (cmd->target == hd->hostid);    cp->cp_datalen = htonl((ulong)cmd->request_bufflen);    cp->Auto_Req_Sen = FALSE;    cp->cp_reqDMA = htonl(0);    cp->reqlen = 0;        cp->cp_id = cmd->target;    cp->cp_lun = cmd->lun;    cp->cp_dispri = FALSE;    cp->cp_identify = TRUE;    memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));        cp->cp_statDMA = htonl(0);        cp->cp_viraddr = cp;    cp->cmd = cmd;    cmd->host_scribble = (char *)&hd->ccb[y];           if (cmd->use_sg == 0)    { 	cmd->SCp.buffers_residual=1;	cmd->SCp.ptr = cmd->request_buffer;	cmd->SCp.this_residual = cmd->request_bufflen;	cmd->SCp.buffer = NULL;    } else {	cmd->SCp.buffer = cmd->request_buffer;	cmd->SCp.buffers_residual = cmd->use_sg;	cmd->SCp.ptr = cmd->SCp.buffer->address;	cmd->SCp.this_residual = cmd->SCp.buffer->length;    }    cmd->SCp.Status = (cmd->SCp.this_residual != 0);  /* TRUE as long as bytes                                                        * are to transfer */         if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))     {	cmd->result = DID_BUS_BUSY << 16;	printk(KERN_NOTICE "eata_pio_queue target %d, pid %ld, HBA busy, "               "returning DID_BUS_BUSY, done.\n", cmd->target, cmd->pid);        done(cmd);        cp->status = FREE;              restore_flags(flags);	return (0);    }    while (!(inb(base + HA_RSTATUS) & HA_SDRQ));    outsw(base + HA_RDATA, cp, hd->cplen);    outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);    for (x = 0; x < hd->cppadlen; x++) outw(0, base + HA_RDATA);        DBG(DBG_QUEUE,printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x "                         "lun: %x slot %d irq %d\n", (long)sh->base, cmd->pid, 			 cmd->target, cmd->lun, y, sh->irq));    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));        restore_flags(flags);    return (0);}int eata_pio_abort(Scsi_Cmnd * cmd){    ulong flags;    uint loop = HZ;        save_flags(flags);    cli();        DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld "                           "target: %x lun: %x reason %x\n", cmd->pid,                            cmd->target, cmd->lun, cmd->abort_reason));    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));            while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)	if (--loop == 0) {	    printk(KERN_WARNING "eata_pio: abort, timeout error.\n");	    restore_flags(flags);	    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	    return (SCSI_ABORT_ERROR);	}    if (CD(cmd)->status == FREE) {	DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n")); 	restore_flags(flags);	return (SCSI_ABORT_NOT_RUNNING);    }    if (CD(cmd)->status == USED) {	DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n"));	restore_flags(flags);	return (SCSI_ABORT_BUSY);  /* SNOOZE */     }    if (CD(cmd)->status == RESET) {	restore_flags(flags);	printk(KERN_WARNING "eata_pio: abort, command reset error.\n");	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_ABORT_ERROR);    }    if (CD(cmd)->status == LOCKED) {	restore_flags(flags);	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot "                               "locked.\n"));	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_ABORT_NOT_RUNNING);    }    restore_flags(flags);    panic("eata_pio: abort: invalid slot status\n");}int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy){    uint x, time, limit = 0;    ulong flags;    unchar success = FALSE;    Scsi_Cmnd *sp;         save_flags(flags);    cli();    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset called pid:%ld target:"                           " %x lun: %x reason %x\n", cmd->pid, cmd->target,                            cmd->lun, cmd->abort_reason));    if (HD(cmd)->state == RESET) {	printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");	restore_flags(flags);	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_RESET_ERROR);    }        /* force all slots to be free */        for (x = 0; x < cmd->host->can_queue; x++) {		if (HD(cmd)->ccb[x].status == FREE) 	    continue;		sp = HD(cmd)->ccb[x].cmd;	HD(cmd)->ccb[x].status = RESET;	printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x,               sp->pid);	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));		if (sp == NULL)	    panic("eata_pio_reset: slot %d, sp==NULL.\n", x);	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));    }        /* hard reset the HBA  */    outb(EATA_CMD_RESET, (uint) cmd->host->base+HA_WCOMMAND);        DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));    HD(cmd)->state = RESET;        time = jiffies;    while (jiffies < (time + (3 * HZ)) && limit++ < 10000000);        DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, "                           "loops %d.\n", limit));    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));        for (x = 0; x < cmd->host->can_queue; x++) {		/* Skip slots already set free by interrupt */	if (HD(cmd)->ccb[x].status != RESET)	    continue;		sp = HD(cmd)->ccb[x].cmd;	sp->result = DID_RESET << 16;		/* This mailbox is terminated */	printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n",x);	HD(cmd)->ccb[x].status = FREE;		restore_flags(flags);	sp->scsi_done(sp);	cli();    }        HD(cmd)->state = FALSE;    restore_flags(flags);        if (success) { /* hmmm... */	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));	return (SCSI_RESET_SUCCESS);    } else {	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));

⌨️ 快捷键说明

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