!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/scsi/   drwxr-xr-x
Free 318.37 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     eata_dma.c (45.42 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/************************************************************
 *                                *
 *            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/slab.h>
#include <linux/in.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>
#include <linux/spinlock.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 */

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_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 MODULE
int 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]--;
    
    kfree((void *)status);
    kfree((void *)dma_scratch - 4);
    for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */
    if(SD(sh)->ccb[i].sg_list != NULL)
        kfree((void *) SD(sh)->ccb[i].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);
}
#endif


inline 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, void *, struct pt_regs *);

void do_eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
{
    unsigned long flags;

    spin_lock_irqsave(&io_request_lock, flags);
    eata_int_handler(irq, dev_id, regs);
    spin_unlock_irqrestore(&io_request_lock, flags);
}

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);

    /*
     * This is overkill.....but the MIPSen seem to need this
     * and it will be optimized away for i86 and ALPHA machines.
     */
    flush_cache_all();

    /* And now the address in nice little byte chunks */
#ifdef __LITTLE_ENDIAN
    outb(addr,       base + HA_WDMAADDR);
    outb(addr >> 8,  base + HA_WDMAADDR + 1);
    outb(addr >> 16, base + HA_WDMAADDR + 2);
    outb(addr >> 24, base + HA_WDMAADDR + 3);
#else
    outb(addr >> 24, base + HA_WDMAADDR);
    outb(addr >> 16, base + HA_WDMAADDR + 1);
    outb(addr >> 8,  base + HA_WDMAADDR + 2);
    outb(addr,       base + HA_WDMAADDR + 3);
#endif
    outb(command, base + HA_WCOMMAND);
    return(TRUE);
}

inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2)
{
    if(addr != (u32) NULL)
        addr = virt_to_bus((void *)addr);

    /*
     * This is overkill.....but the MIPSen seem to need this
     * and it will be optimized away for i86 and ALPHA machines.
     */
    flush_cache_all();

    outb(0x0, base + HA_WDMAADDR - 1);
    if(addr){
#ifdef __LITTLE_ENDIAN
        outb(addr,       base + HA_WDMAADDR);
    outb(addr >> 8,  base + HA_WDMAADDR + 1);
    outb(addr >> 16, base + HA_WDMAADDR + 2);
    outb(addr >> 24, base + HA_WDMAADDR + 3);
#else
        outb(addr >> 24, base + HA_WDMAADDR);
    outb(addr >> 16, base + HA_WDMAADDR + 1);
    outb(addr >> 8,  base + HA_WDMAADDR + 2);
    outb(addr,       base + HA_WDMAADDR + 3);
#endif
    } else {
        outb(0x0, base + HA_WDMAADDR);
        outb(0x0, base + HA_WDMAADDR + 1);
     outb(code2, base + HA_WCODE2);
    outb(code,  base + HA_WCODE);
    }
    
    outb(ifc, base + HA_WIFC);
    outb(EATA_CMD_IMMEDIATE, base + HA_WCOMMAND);
    return(TRUE);
}

int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
{
    unsigned int i, x, y;
    ulong flags;
    hostdata *hd;
    struct Scsi_Host *sh;
    struct eata_ccb *ccb;
    struct scatterlist *sl;

    
    save_flags(flags);
    cli();

#if 0
    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
      if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
            printk("eata_dma: scsi%d interrupt pending in eata_queue.\n"
           "          Calling interrupt handler.\n", sh->host_no);
            eata_int_handler(sh->irq, 0, 0);
      }
    }
#endif
    
    queue_counter++;

    hd = HD(cmd);
    sh = cmd->host;
    
    if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
        DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
    cmd->result = DID_OK << 16;
    done(cmd);
    restore_flags(flags);

    return(0);
    }

    /* check for free slot */
    for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 
    if (y >= sh->can_queue)
        y = 0;
    if (hd->ccb[y].status == FREE)
        break;
    }
    
    hd->last_ccb = y;

    if (x >= sh->can_queue) { 
    cmd->result = DID_BUS_BUSY << 16;
    DBG(DBG_QUEUE && DBG_ABNORM, 
        printk(KERN_CRIT "eata_queue pid %ld, HBA QUEUE FULL..., "
           "returning DID_BUS_BUSY\n", cmd->pid));
    done(cmd);
    restore_flags(flags);
    return(0);
    }
    ccb = &hd->ccb[y];
    
    memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
    
    ccb->status = USED;            /* claim free slot */

    restore_flags(flags);
    
    DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
              cmd->pid, cmd->target, cmd->lun, y));
    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
    
    if(hd->do_latency == TRUE) 
        eata_latency_out(ccb, cmd);

    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 */
    ccb->DataOut = TRUE;    /* Output mode */
    break;
    case TEST_UNIT_READY:
    default:
    ccb->DataIn = TRUE;    /* Input mode  */
    }

    /* FIXME: This will will have to be changed once the midlevel driver 
     *        allows different HBA IDs on every channel.
     */
    if (cmd->target == sh->this_id) 
    ccb->Interpret = TRUE;    /* Interpret command */

    if (cmd->use_sg) {
    ccb->scatter = TRUE;    /* SG mode     */
    if (ccb->sg_list == NULL) {
        ccb->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),
                  GFP_ATOMIC | GFP_DMA);
    }
    if (ccb->sg_list == NULL)
    {
        /*
         *    Claim the bus was busy. Actually we are the problem but this
         *  will do a deferred retry for us ;)
         */
        printk(KERN_ERR "eata_dma: Run out of DMA memory for SG lists !\n");
        cmd->result = DID_BUS_BUSY << 16;
        ccb->status = FREE;    
        done(cmd);
        return(0);
    }
    ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list)); 
    
    ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
    sl=(struct scatterlist *)cmd->request_buffer;
    for(i = 0; i < cmd->use_sg; i++, sl++){
        ccb->sg_list[i].data = htonl(virt_to_bus(sl->address));
        ccb->sg_list[i].len = htonl((u32) sl->length);
    }
    } else {
    ccb->scatter = FALSE;
    ccb->cp_datalen = htonl(cmd->request_bufflen);
    ccb->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));
    }
    
    ccb->Auto_Req_Sen = TRUE;
    ccb->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));
    ccb->reqlen = sizeof(cmd->sense_buffer);
    
    ccb->cp_id = cmd->target;
    ccb->cp_channel = cmd->channel;
    ccb->cp_lun = cmd->lun;
    ccb->cp_dispri = TRUE;
    ccb->cp_identify = TRUE;
    memcpy(ccb->cp_cdb, cmd->cmnd, cmd->cmd_len);
    
    ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
    
    ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to 
                * convert it */
    ccb->cmd = cmd;
    cmd->host_scribble = (char *)&hd->ccb[y];    
    
    if(eata_send_command((u32) ccb, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
    cmd->result = DID_BUS_BUSY << 16;
    DBG(DBG_QUEUE && DBG_ABNORM, 
        printk("eata_queue target %d, pid %ld, HBA busy, "
           "returning DID_BUS_BUSY\n",cmd->target, cmd->pid));
    ccb->status = FREE;    
    done(cmd);
    return(0);
    }
    DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "
             "slot %d irq %d\n", (s32)sh->base, cmd->pid, 
             cmd->target, cmd->lun, y, sh->irq));
    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));

    return(0);
}


int eata_abort(Scsi_Cmnd * cmd)
{
    ulong loop = HZ / 2;
    ulong flags;
    int x;
    struct Scsi_Host *sh;
 
    save_flags(flags);
    cli();

    DBG(DBG_ABNORM, printk("eata_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));

    /* Some interrupt controllers seem to loose interrupts */
    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
        if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
            printk("eata_dma: scsi%d interrupt pending in eata_abort.\n"
           "          Calling interrupt handler.\n", sh->host_no);
        eata_int_handler(sh->irq, 0, 0);
    }
    }

    while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) {
    if (--loop == 0) {
        printk("eata_dma: abort, timeout error.\n");
        DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        restore_flags(flags);
        return (SCSI_ABORT_ERROR);
    }
    }
    if (CD(cmd)->status == RESET) {
    printk("eata_dma: abort, command reset error.\n");
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    restore_flags(flags);
    return (SCSI_ABORT_ERROR);
    }
    if (CD(cmd)->status == LOCKED) {
    DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    restore_flags(flags);
    return (SCSI_ABORT_NOT_RUNNING);
    }
    if (CD(cmd)->status == USED) {
    DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
    restore_flags(flags);
    return (SCSI_ABORT_BUSY);  /* SNOOZE */ 
    }
    if (CD(cmd)->status == FREE) {
    DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 
    restore_flags(flags);
    return (SCSI_ABORT_NOT_RUNNING);
    }
    restore_flags(flags);
    panic("eata_dma: abort: invalid slot status\n");
}

int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags)
{
    uint x; 
    /* 10 million PCI reads take at least one third of a second */
    ulong loop = 10 * 1000 * 1000;
    ulong flags;
    unchar success = FALSE;
    Scsi_Cmnd *sp; 
    struct Scsi_Host *sh;
    
    save_flags(flags);
    cli();
    
    DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x"
               " reason %x\n", cmd->pid, cmd->target, cmd->lun, 
               cmd->abort_reason));
    
    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
        if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
            printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"
           "          Calling interrupt handler.\n", sh->host_no);
            eata_int_handler(sh->irq, 0, 0);
      }
    }

    if (HD(cmd)->state == RESET) {
    printk("eata_reset: exit, already in reset.\n");
    restore_flags(flags);
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    return (SCSI_RESET_ERROR);
    }
    
    while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
    if (--loop == 0) {
        printk("eata_reset: exit, timeout error.\n");
        restore_flags(flags);
        DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_ERROR);
    }
 
    for (x = 0; x < cmd->host->can_queue; x++) {
    if (HD(cmd)->ccb[x].status == FREE)
        continue;

    if (HD(cmd)->ccb[x].status == LOCKED) {
        HD(cmd)->ccb[x].status = FREE;
        printk("eata_reset: locked slot %d forced free.\n", x);
        DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        continue;
    }


    sp = HD(cmd)->ccb[x].cmd;
    HD(cmd)->ccb[x].status = RESET;
    
    if (sp == NULL)
        panic("eata_reset: slot %d, sp==NULL.\n", x);

    printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);

    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    
    if (sp == cmd)
        success = TRUE;
    }
    
    /* hard reset the HBA  */
    inb((u32) (cmd->host->base) + HA_RSTATUS);    /* This might cause trouble */
    eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET);
    
    HD(cmd)->state = RESET;

    DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling "
               "interrupts.\n"));

    DELAY(2); /* In theorie we should get interrupts and set free all
           * used queueslots */
    
    DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled again.\n"));
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    
    for (x = 0; x < cmd->host->can_queue; x++) {
    
    /* Skip slots already set free by interrupt and those that 
         * are still LOCKED from the last reset */
    if (HD(cmd)->ccb[x].status != RESET)
        continue;
    
    sp = HD(cmd)->ccb[x].cmd;
    sp->result = DID_RESET << 16;
    
    /* This mailbox is still waiting for its interrupt */
    HD(cmd)->ccb[x].status = LOCKED;
    
    printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",
           x, sp->pid);
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));

    sp->scsi_done(sp);
    }
    
    HD(cmd)->state = FALSE;
    restore_flags(flags);
    
    if (success) {
    DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n"));
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    return (SCSI_RESET_PENDING);
    } else {
    DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
    return (SCSI_RESET_PUNT);
    }
}

/* Here we try to determine the optimum queue depth for
 * each attached device.
 *
 * At the moment the algorithm is rather simple
 */
static void eata_select_queue_depths(struct Scsi_Host *host, 
                     Scsi_Device *devicelist)
{
    Scsi_Device *device;
    int devcount = 0; 
    int factor = 0;

#if CRIPPLE_QUEUE    
    for(device = devicelist; device != NULL; device = device->next) {
        if(device->host == host)
        device->queue_depth = 2;
    }
#else
    /* First we do a sample run go find out what we have */
    for(device = devicelist; device != NULL; device = device->next) {
        if (device->host == host) {
        devcount++;
        switch(device->type) {
        case TYPE_DISK:
        case TYPE_MOD:
            factor += TYPE_DISK_QUEUE;
        break;
        case TYPE_TAPE:
            factor += TYPE_TAPE_QUEUE;
        break;
        case TYPE_WORM:
        case TYPE_ROM:
            factor += TYPE_ROM_QUEUE;
        break;
        case TYPE_PROCESSOR:
        case TYPE_SCANNER:
        default:
            factor += TYPE_OTHER_QUEUE;
        break;
        }
    }
    }

    DBG(DBG_REGISTER, printk(KERN_DEBUG "scsi%d: needed queueslots %d\n", 
                 host->host_no, factor));

    if(factor == 0)    /* We don't want to get a DIV BY ZERO error */
        factor = 1;

    factor = (SD(host)->queuesize * 10) / factor;

    DBG(DBG_REGISTER, printk(KERN_DEBUG "scsi%d: using factor %dE-1\n", 
                 host->host_no, factor));

    /* Now that have the factor we can set the individual queuesizes */
    for(device = devicelist; device != NULL; device = device->next) {
        if(device->host == host) {
        if(SD(device->host)->bustype != IS_ISA){
            switch(device->type) {
        case TYPE_DISK:
        case TYPE_MOD:
            device->queue_depth = (TYPE_DISK_QUEUE * factor) / 10;
            break;
        case TYPE_TAPE:
            device->queue_depth = (TYPE_TAPE_QUEUE * factor) / 10;
            break;
        case TYPE_WORM:
        case TYPE_ROM:
                device->queue_depth = (TYPE_ROM_QUEUE * factor) / 10;
            break;
        case TYPE_PROCESSOR:
        case TYPE_SCANNER:
        default:
            device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10;
            break;
        }
        } else /* ISA forces us to limit the queue depth because of the 
            * bounce buffer memory overhead. I know this is cruel */
            device->queue_depth = 2; 

        /* 
         * It showed that we need to set an upper limit of commands 
             * we can allow to  queue for a single device on the bus. 
         * If we get above that limit, the broken midlevel SCSI code 
         * will produce bogus timeouts and aborts en masse. :-(
         */
        if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT)
        device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT;
        if(device->queue_depth == 0) 
        device->queue_depth = 1;

        printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
           "set to %d\n", host->host_no, device->id, device->channel,
           device->queue_depth);
    }
    }
#endif
}

#if CHECK_BLINK
int check_blink_state(long base)
{
    ushort loops = 10;
    u32 blinkindicator;
    u32 state = 0x12345678;
    u32 oldstate = 0;

    blinkindicator = htonl(0x54504442);
    while ((loops--) && (state != oldstate)) {
    oldstate = state;
    state = inl((uint) base + 1);
    }

    DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
          (state == oldstate) && (state == blinkindicator)));

    if ((state == oldstate) && (state == blinkindicator))
    return(TRUE);
    else
    return (FALSE);
}
#endif

char * get_board_data(u32 base, u32 irq, u32 id)
{
    struct eata_ccb *cp;
    struct eata_sp  *sp;
    static char *buff;
    ulong i;

    cp = (struct eata_ccb *) kmalloc(sizeof(struct eata_ccb),
                     GFP_ATOMIC | GFP_DMA);
                     
    if(cp==NULL)
        return NULL;
        
    sp = (struct eata_sp *) kmalloc(sizeof(struct eata_sp), 
                         GFP_ATOMIC | GFP_DMA);
    if(sp==NULL)
    {
        kfree(cp);
        return NULL;
    }                  

    buff = dma_scratch;
 
    memset(cp, 0, sizeof(struct eata_ccb));
    memset(sp, 0, sizeof(struct eata_sp));
    memset(buff, 0, 256);

    cp->DataIn = TRUE;       
    cp->Interpret = TRUE;   /* Interpret command */
    cp->cp_dispri = TRUE;
    cp->cp_identify = TRUE;
 
    cp->cp_datalen = htonl(56);  
    cp->cp_dataDMA = htonl(virt_to_bus(buff));
    cp->cp_statDMA = htonl(virt_to_bus(sp));
    cp->cp_viraddr = cp;
    
    cp->cp_id = id;
    cp->cp_lun = 0;

    cp->cp_cdb[0] = INQUIRY;
    cp->cp_cdb[1] = 0;
    cp->cp_cdb[2] = 0;
    cp->cp_cdb[3] = 0;
    cp->cp_cdb[4] = 56;
    cp->cp_cdb[5] = 0;

    fake_int_base = (struct eata_register *) base;
    fake_int_result = FALSE;
    fake_int_happened = FALSE;

    eata_send_command((u32) cp, (u32) base, EATA_CMD_DMA_SEND_CP);
    
    i = jiffies + (3 * HZ);
    while (fake_int_happened == FALSE && time_before_eq(jiffies, i)) 
    barrier();
    
    DBG(DBG_INTR3, printk(KERN_DEBUG "fake_int_result: %#x hbastat %#x "
              "scsistat %#x, buff %p sp %p\n",
              fake_int_result, (u32) (sp->hba_stat /*& 0x7f*/), 
              (u32) sp->scsi_stat, buff, sp));

    kfree((void *)cp);
    kfree((void *)sp);
    
    if ((fake_int_result & HA_SERROR) || time_after(jiffies, i)){
    printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear "
           "possible blink state\n", base); 
    /* hard reset the HBA  */
    inb((u32) (base) + HA_RSTATUS);
    eata_send_command(0, base, EATA_CMD_RESET);
    DELAY(1);
    return (NULL);
    } else
    return (buff);
}


int get_conf_PIO(u32 base, struct get_conf *buf)
{
    ulong loop = R_LIMIT;
    u16 *p;

    if(check_region(base, 9)) 
    return (FALSE);
     
    memset(buf, 0, sizeof(struct get_conf));

    while (inb(base + HA_RSTATUS) & HA_SBUSY)
    if (--loop == 0) 
        return (FALSE);

    fake_int_base = (struct eata_register *) base;
    fake_int_result = FALSE;
    fake_int_happened = FALSE;
       
    DBG(DBG_PIO && DBG_PROBE,
    printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
    eata_send_command(0, base, EATA_CMD_PIO_READ_CONFIG);

    loop = R_LIMIT;
    for (p = (u16 *) buf; 
     (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
    while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
        if (--loop == 0)
        return (FALSE);

    loop = R_LIMIT;
    *p = inw(base + HA_RDATA);
    }

    if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {        /* Error ? */
    if (htonl(EATA_SIGNATURE) == buf->signature) {
        DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %x "
                       "EATA Level: %x\n", (uint) base, 
                       (uint) (buf->version)));
        
        while (inb(base + HA_RSTATUS) & HA_SDRQ) 
        inw(base + HA_RDATA);
        return (TRUE);
    } 
    } else {
    DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
          "for HBA at %lx\n", (long)base));
    }
    return (FALSE);
}


void print_config(struct get_conf *gc)
{
    printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
       (u32) ntohl(gc->len), gc->version,
       gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
       gc->DMA_support);
    printk("DMAV:%d HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
       gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
       gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
    printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d SG_64K:%d SG_UAE:%d MID:%d "
       "MCH:%d MLUN:%d\n",
       gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR, 
       gc->SG_64K, gc->SG_UAE, gc->MAX_ID, gc->MAX_CHAN, gc->MAX_LUN); 
    printk("RIDQ:%d PCI:%d EISA:%d\n",
       gc->ID_qest, gc->is_PCI, gc->is_EISA);
    DBG(DPT_DEBUG, DELAY(14));
}

short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, 
           u8 bustype)
{
    ulong size = 0;
    unchar dma_channel = 0;
    char *buff = 0;
    unchar bugs = 0;
    struct Scsi_Host *sh;
    hostdata *hd;
    int x;
    
    
    DBG(DBG_REGISTER, print_config(gc));

    if (gc->DMA_support == FALSE) {
    printk("The EATA HBA at %#.4x does not support DMA.\n" 
           "Please use the EATA-PIO driver.\n", base);
    return (FALSE);
    }
    if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22) 
    gc->MAX_CHAN = 0;

    if (reg_IRQ[gc->IRQ] == FALSE) {    /* Interrupt already registered ? */
    if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT,
             "eata_dma", NULL)){
        reg_IRQ[gc->IRQ]++;
        if (!gc->IRQ_TR)
        reg_IRQL[gc->IRQ] = TRUE;   /* IRQ is edge triggered */
    } else {
        printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
        return (FALSE);
    }
    } else {        /* More than one HBA on this IRQ */
    if (reg_IRQL[gc->IRQ] == TRUE) {
        printk("Can't support more than one HBA on this IRQ,\n"
           "  if the IRQ is edge triggered. Sorry.\n");
        return (FALSE);
    } else
        reg_IRQ[gc->IRQ]++;
    }

 
    /* If DMA is supported but DMA_valid isn't set to indicate that
     * the channel number is given we must have pre 2.0 firmware (1.7?)
     * which leaves us to guess since the "newer ones" also don't set the 
     * DMA_valid bit.
     */
    if (gc->DMA_support && !gc->DMA_valid && gc->DMA_channel) {
      printk(KERN_WARNING "eata_dma: If you are using a pre 2.0 firmware "
         "please update it !\n"
         "          You can get new firmware releases from ftp.dpt.com\n");
    gc->DMA_channel = (base == 0x1f0 ? 3 /* DMA=5 */ : 2 /* DMA=6 */);
    gc->DMA_valid = TRUE;
    }

    /* if gc->DMA_valid it must be an ISA HBA and we have to register it */
    dma_channel = BUSMASTER;
    if (gc->DMA_valid) {
    if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
        printk(KERN_WARNING "Unable to allocate DMA channel %d for ISA HBA"
           " at %#.4x.\n", dma_channel, base);
        reg_IRQ[gc->IRQ]--;
        if (reg_IRQ[gc->IRQ] == 0)
        free_irq(gc->IRQ, NULL);
        if (gc->IRQ_TR == FALSE)
        reg_IRQL[gc->IRQ] = FALSE; 
        return (FALSE);
    }
    }

    if (dma_channel != BUSMASTER) {
    disable_dma(dma_channel);
    clear_dma_ff(dma_channel);
    set_dma_mode(dma_channel, DMA_MODE_CASCADE);
    enable_dma(dma_channel);
    }

    if (bustype != IS_EISA && bustype != IS_ISA)
    buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);

    if (buff == NULL) {
    if (bustype == IS_EISA || bustype == IS_ISA) {
        bugs = bugs || BROKEN_INQUIRY;
    } else {
        if (gc->DMA_support == FALSE)
        printk(KERN_WARNING "HBA at %#.4x doesn't support DMA. "
               "Sorry\n", base);
        else
        printk(KERN_WARNING "HBA at %#.4x does not react on INQUIRY. "
               "Sorry.\n", base);
        if (gc->DMA_valid) 
        free_dma(dma_channel);
        reg_IRQ[gc->IRQ]--;
        if (reg_IRQ[gc->IRQ] == 0)
        free_irq(gc->IRQ, NULL);
        if (gc->IRQ_TR == FALSE)
        reg_IRQL[gc->IRQ] = FALSE; 
        return (FALSE);
    }
    }
 
    if (gc->DMA_support == FALSE && buff != NULL)  
    printk(KERN_WARNING "HBA %.12sat %#.4x doesn't set the DMA_support "
           "flag correctly.\n", &buff[16], base);
    
    request_region(base, 9, "eata_dma"); /* We already checked the 
                      * availability, so this
                      * should not fail.
                      */
    
    if(ntohs(gc->queuesiz) == 0) {
    gc->queuesiz = ntohs(64);
    printk(KERN_WARNING "Warning: Queue size has to be corrected. Assuming"
           " 64 queueslots\n"
           "         This might be a PM2012B with a defective Firmware\n"
           "         Contact DPT support@dpt.com for an upgrade\n");
    }

    size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long)) 
                   * ntohs(gc->queuesiz));

    DBG(DBG_REGISTER, printk("scsi_register size: %ld\n", size));

    sh = scsi_register(tpnt, size);
    
    if(sh != NULL) {

        hd = SD(sh);           

    memset(hd->reads, 0, sizeof(u32) * 26); 
    
    sh->select_queue_depths = eata_select_queue_depths;
    
    hd->bustype = bustype;

    /*
     * If we are using a ISA board, we can't use extended SG,
     * because we would need excessive amounts of memory for
     * bounce buffers.
     */
    if (gc->SG_64K==TRUE && ntohs(gc->SGsiz)==64 && hd->bustype!=IS_ISA){
        sh->sg_tablesize = SG_SIZE_BIG;
    } else {
        sh->sg_tablesize = ntohs(gc->SGsiz);
        if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
            if (sh->sg_tablesize == 0)
            printk(KERN_WARNING "Warning: SG size had to be fixed.\n"
               "This might be a PM2012 with a defective Firmware"
               "\nContact DPT support@dpt.com for an upgrade\n");
        sh->sg_tablesize = SG_SIZE;
        }
    }
    hd->sgsize = sh->sg_tablesize;
    }

    if(sh != NULL) {
        sh->can_queue = hd->queuesize = ntohs(gc->queuesiz);
           sh->cmd_per_lun = 0;
    }

    if(sh == NULL) { 
        DBG(DBG_REGISTER, printk(KERN_NOTICE "eata_dma: couldn't register HBA"
                 " at%x \n", base));
    scsi_unregister(sh);
    if (gc->DMA_valid) 
        free_dma(dma_channel);
    
    reg_IRQ[gc->IRQ]--;
    if (reg_IRQ[gc->IRQ] == 0)
        free_irq(gc->IRQ, NULL);
    if (gc->IRQ_TR == FALSE)
        reg_IRQL[gc->IRQ] = FALSE; 
    return (FALSE);
    }

    
    hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY);

    if(hd->broken_INQUIRY == TRUE) {
    strcpy(hd->vendor, "DPT");
    strcpy(hd->name, "??????????");
    strcpy(hd->revision, "???.?");
        hd->firmware_revision = 0;
    } else {    
    strncpy(hd->vendor, &buff[8], 8);
    hd->vendor[8] = 0;
    strncpy(hd->name, &buff[16], 17);
    hd->name[17] = 0;
    hd->revision[0] = buff[32];
    hd->revision[1] = buff[33];
    hd->revision[2] = buff[34];
    hd->revision[3] = '.';
    hd->revision[4] = buff[35];
    hd->revision[5] = 0;
        hd->firmware_revision = (buff[32] << 24) + (buff[33] << 16) 
                                + (buff[34] << 8) + buff[35]; 
    }

    if (hd->firmware_revision >= (('0'<<24) + ('7'<<16) + ('G'<< 8) + '0'))
        hd->immediate_support = 1;
    else 
        hd->immediate_support = 0;

    switch (ntohl(gc->len)) {
    case 0x1c:
    hd->EATA_revision = 'a';
    break;
    case 0x1e:
    hd->EATA_revision = 'b';
    break;
    case 0x22:
    hd->EATA_revision = 'c';
    break;
    case 0x24:
    hd->EATA_revision = 'z';        
    default:
    hd->EATA_revision = '?';
    }


    if(ntohl(gc->len) >= 0x22) {
    sh->max_id = gc->MAX_ID + 1;
    sh->max_lun = gc->MAX_LUN + 1;
    } else {
    sh->max_id = 8;
    sh->max_lun = 8;
    }

    hd->HBA_number = sh->host_no;
    hd->channel = gc->MAX_CHAN;        
    sh->max_channel = gc->MAX_CHAN; 
    sh->unique_id = base;
    sh->base = base;
    sh->io_port = base;
    sh->n_io_port = 9;
    sh->irq = gc->IRQ;
    sh->dma_channel = dma_channel;
    
    /* FIXME:
     * SCSI midlevel code should support different HBA ids on every channel
     */
    sh->this_id = gc->scsi_id[3];
    
    if (gc->SECOND)
    hd->primary = FALSE;
    else
    hd->primary = TRUE;
    
    if (hd->bustype != IS_ISA) {
    sh->unchecked_isa_dma = FALSE;
    } else {
    sh->unchecked_isa_dma = TRUE;    /* We're doing ISA DMA */
    }
    
    for(x = 0; x <= 11; x++){         /* Initialize min. latency */
    hd->writes_lat[x][1] = 0xffffffff;
    hd->reads_lat[x][1] = 0xffffffff;
    }
    hd->all_lat[1] = 0xffffffff;

    hd->next = NULL;    /* build a linked list of all HBAs */
    hd->prev = last_HBA;
    if(hd->prev != NULL)
    SD(hd->prev)->next = sh;
    last_HBA = sh;
    if (first_HBA == NULL)
    first_HBA = sh;
    registered_HBAs++;
    
    return (TRUE);
}



void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
    u32 base;
    int i;
    
#if CHECKPAL
    u8 pal1, pal2, pal3;
#endif
    
    for (i = 0; i < MAXEISA; i++) {
    if (EISAbases[i] == TRUE) { /* Still a possibility ?          */
        
        base = 0x1c88 + (i * 0x1000);
#if CHECKPAL
        pal1 = inb((u16)base - 8);
        pal2 = inb((u16)base - 7);
        pal3 = inb((u16)base - 6);
        
        if (((pal1 == DPT_ID1) && (pal2 == DPT_ID2)) ||
        ((pal1 == NEC_ID1) && (pal2 == NEC_ID2) && (pal3 == NEC_ID3))||
        ((pal1 == ATT_ID1) && (pal2 == ATT_ID2) && (pal3 == ATT_ID3))){
        DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
                      (int)pal1, (int)pal2, (int)pal3));
#endif
        if (get_conf_PIO(base, buf) == TRUE) {
            if (buf->IRQ) {  
            DBG(DBG_EISA, printk("Registering EISA HBA\n"));
            register_HBA(base, buf, tpnt, IS_EISA);
            } else
            printk("eata_dma: No valid IRQ. HBA removed from list\n");
        }
#if CHECK_BLINK
        else {
            if (check_blink_state(base)) 
            printk("HBA is in BLINK state. Consult your HBAs "
                   "Manual to correct this.\n");
        } 
#endif
        /* Nothing found here so we take it from the list */
        EISAbases[i] = 0;  
#if CHECKPAL
        } 
#endif
    }
    }
    return; 
}

void find_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
    int i;
    
    for (i = 0; i < MAXISA; i++) {  
    if (ISAbases[i]) {  
        if (get_conf_PIO(ISAbases[i],buf) == TRUE){
        DBG(DBG_ISA, printk("Registering ISA HBA\n"));
        register_HBA(ISAbases[i], buf, tpnt, IS_ISA);
        } 
#if CHECK_BLINK
        else {
        if (check_blink_state(ISAbases[i])) 
            printk("HBA is in BLINK state. Consult your HBAs "
               "Manual to correct this.\n");
        }
#endif
        ISAbases[i] = 0;
    }
    }
    return;
}

void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
#ifndef CONFIG_PCI
    printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
#else
    struct pci_dev *dev = NULL; 
    u32 base, x;
    u8 pal1, pal2, pal3;

    while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
        DBG(DBG_PROBE && DBG_PCI, 
        printk("eata_dma: find_PCI, HBA at %s\n", dev->name));
        if (pci_enable_device(dev))
            continue;
        pci_set_master(dev);
        base = pci_resource_flags(dev, 0);
        if (base & IORESOURCE_MEM) {
        printk("eata_dma: invalid base address of device %s\n", dev->name);
        continue;
        }
        base = pci_resource_start(dev, 0);
            /* EISA tag there ? */
        pal1 = inb(base);
        pal2 = inb(base + 1);
        pal3 = inb(base + 2);
        if (((pal1 == DPT_ID1) && (pal2 == DPT_ID2)) ||
        ((pal1 == NEC_ID1) && (pal2 == NEC_ID2) && 
        (pal3 == NEC_ID3)) ||
        ((pal1 == ATT_ID1) && (pal2 == ATT_ID2) && 
        (pal3 == ATT_ID3)))
        base += 0x08;
        else
        base += 0x10;   /* Now, THIS is the real address */
        if (base != 0x1f8) {
        /* We didn't find it in the primary search */
        if (get_conf_PIO(base, buf) == TRUE) {
            /* OK. We made it till here, so we can go now  
             * and register it. We only have to check and 
             * eventually remove it from the EISA and ISA list 
             */
            DBG(DBG_PCI, printk("Registering PCI HBA\n"));
            register_HBA(base, buf, tpnt, IS_PCI);
            
            if (base < 0x1000) {
            for (x = 0; x < MAXISA; ++x) {
                if (ISAbases[x] == base) {
                ISAbases[x] = 0;
                break;
                }
            }
            } else if ((base & 0x0fff) == 0x0c88) 
            EISAbases[(base >> 12) & 0x0f] = 0;
        } 
#if CHECK_BLINK
        else if (check_blink_state(base) == TRUE) {
            printk("eata_dma: HBA is in BLINK state.\n"
               "Consult your HBAs manual to correct this.\n");
        }
#endif
        }
    }
#endif /* #ifndef CONFIG_PCI */
}

int eata_detect(Scsi_Host_Template * tpnt)
{
    struct Scsi_Host *HBA_ptr;
    struct get_conf gc;
    int i;
    
    DBG((DBG_PROBE && DBG_DELAY) || DPT_DEBUG,
    printk("Using lots of delays to let you read the debugging output\n"));

    tpnt->proc_name = "eata_dma";

    status = kmalloc(512, GFP_ATOMIC | GFP_DMA);
    dma_scratch = kmalloc(1024, GFP_ATOMIC | GFP_DMA);

    if(status == NULL || dma_scratch == NULL) {
    printk("eata_dma: can't allocate enough memory to probe for hosts !\n");
    if(status)
        kfree(status);
    if(dma_scratch)
        kfree(dma_scratch);
    return(0);
    }

    dma_scratch += 4;

    find_PCI(&gc, tpnt);
    
    find_EISA(&gc, tpnt);
    
    find_ISA(&gc, tpnt);
    
    for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we     */
    if (reg_IRQ[i] >= 1){       /* exchange the interrupt handler which  */
        free_irq(i, NULL);      /* we used for probing with the real one */
        request_irq(i, (void *)(do_eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
            "eata_dma", NULL);
    }
    }

    HBA_ptr = first_HBA;

    if (registered_HBAs != 0) {
        printk("EATA (Extended Attachment) driver version: %d.%d%s"
               "\ndeveloped in co-operation with DPT\n"
               "(c) 1993-96 Michael Neuffer, mike@i-Connect.Net\n",
               VER_MAJOR, VER_MINOR, VER_SUB);
        printk("Registered HBAs:");
        printk("\nHBA no. Boardtype    Revis  EATA Bus  BaseIO IRQ"
               " DMA Ch ID Pr QS  S/G IS\n");
        for (i = 1; i <= registered_HBAs; i++) {
            printk("scsi%-2d: %.12s v%s 2.0%c %s %#.4x  %2d",
           HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
           SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? 
           "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
           (u32) HBA_ptr->base, HBA_ptr->irq);
        if(HBA_ptr->dma_channel != BUSMASTER)
        printk("  %2x ", HBA_ptr->dma_channel);
        else
        printk(" %s", "BMST");
        printk(" %d  %d  %c %3d %3d %c\n", 
           SD(HBA_ptr)->channel+1, HBA_ptr->this_id, 
           (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
           HBA_ptr->can_queue, HBA_ptr->sg_tablesize, 
           (SD(HBA_ptr)->immediate_support == TRUE)?'Y':'N'); 
        HBA_ptr = SD(HBA_ptr)->next;
    }
    } else {
    kfree((void *)status);
    }

    kfree((void *)dma_scratch - 4);

    DBG(DPT_DEBUG, DELAY(12));

    return(registered_HBAs);
}

MODULE_LICENSE("GPL");

/* Eventually this will go into an include file, but this will be later */
static Scsi_Host_Template driver_template = EATA_DMA;
#include "scsi_module.c"

/*
 * Overrides for Emacs so that we almost follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-indent-level: 4
 * c-brace-imaginary-offset: 0
 * c-brace-offset: -4
 * c-argdecl-indent: 4
 * c-label-offset: -4
 * c-continued-statement-offset: 4
 * c-continued-brace-offset: 0
 * tab-width: 8
 * End:
 */

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0577 ]--