!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:     mca_53c9x.c (12.08 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx
 *  (and maybe some other) Microchannel machines
 *
 * Code taken mostly from Cyberstorm SCSI drivers
 *   Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
 *
 * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org)
 *
 * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's
 *   ESP driver  * for the Sparc computers. 
 * 
 * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on
 *  the 86C01.  I was on the brink of going ga-ga...
 *
 * Also thanks to Jesper Skov for helping me with info on how the Amiga
 *  does things...
 */

/*
 * This is currently only set up to use one 53c9x card at a time; it could be 
 *  changed fairly easily to detect/use more than one, but I'm not too sure how
 *  many cards that use the 53c9x on MCA systems there are (if, in fact, there
 *  are cards that use them, other than the one built into some NCR systems)...
 *  If anyone requests this, I'll throw it in, otherwise it's not worth the
 *  effort.
 */

/*
 * Info on the 86C01 MCA interface chip at the bottom, if you care enough to
 *  look.
 */

#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/blk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>

#include "scsi.h"
#include "hosts.h"
#include "NCR53C9x.h"
#include "mca_53c9x.h"

#include <asm/dma.h>
#include <linux/mca.h>
#include <asm/irq.h>
#include <asm/mca_dma.h>

#include <asm/pgtable.h>

static int  dma_bytes_sent(struct NCR_ESP *, int);
static int  dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *);
static void dma_dump_state(struct NCR_ESP *);
static void dma_init_read(struct NCR_ESP *, __u32, int);
static void dma_init_write(struct NCR_ESP *, __u32, int);
static void dma_ints_off(struct NCR_ESP *);
static void dma_ints_on(struct NCR_ESP *);
static int  dma_irq_p(struct NCR_ESP *);
static int  dma_ports_p(struct NCR_ESP *);
static void dma_setup(struct NCR_ESP *, __u32, int, int);
static void dma_led_on(struct NCR_ESP *);
static void dma_led_off(struct NCR_ESP *);

/* This is where all commands are put before they are trasfered to the 
 *  53c9x via PIO.
 */

static volatile unsigned char cmd_buffer[16];

/*
 * We keep the structure that is used to access the registers on the 53c9x
 *  here.
 */

static struct ESP_regs eregs;

/***************************************************************** Detection */
int mca_esp_detect(Scsi_Host_Template *tpnt)
{
    struct NCR_ESP *esp;
    static int io_port_by_pos[] = MCA_53C9X_IO_PORTS;
    int mca_53c9x_ids[] = MCA_53C9X_IDS;
    int *id_to_check = mca_53c9x_ids;
    int slot;
    int pos[3];
    unsigned int tmp_io_addr;
    unsigned char tmp_byte;


    if (!MCA_bus)
        return 0;

    while (*id_to_check) { 
        if ((slot = mca_find_adapter(*id_to_check, 0)) !=
          MCA_NOTFOUND) 
        {
            esp = esp_allocate(tpnt, (void *) NULL);

            pos[0] = mca_read_stored_pos(slot, 2);
            pos[1] = mca_read_stored_pos(slot, 3);
            pos[2] = mca_read_stored_pos(slot, 4);

            esp->eregs = &eregs;

            /*
             * IO port base is given in the first (non-ID) pos
             *  register, like so:
             *
             *  Bits 3  2  1       IO base
             * ----------------------------
             *       0  0  0       <disabled>
             *       0  0  1       0x0240
             *       0  1  0       0x0340
             *       0  1  1       0x0400
             *       1  0  0       0x0420
             *       1  0  1       0x3240
             *       1  1  0       0x8240
             *       1  1  1       0xA240
             */

            tmp_io_addr =
              io_port_by_pos[(pos[0] & 0x0E) >> 1];

            esp->eregs->io_addr = tmp_io_addr + 0x10;

                  if (esp->eregs->io_addr == 0x0000) { 
                    printk("Adapter is disabled.\n");
                break;
            }

            /*
             * IRQ is specified in bits 4 and 5:
             *
             *  Bits  4  5        IRQ
             * -----------------------
             *        0  0         3
             *        0  1         5
             *        1  0         7
             *        1  1         9
             */

                  esp->irq = ((pos[0] & 0x30) >> 3) + 3;

            /*
             * DMA channel is in the low 3 bits of the second
             *  POS register
             */

            esp->dma = pos[1] & 7;
            esp->slot = slot;

            if (request_irq(esp->irq, esp_intr, 0,
             "NCR 53c9x SCSI", esp_intr))
            {
                printk("Unable to request IRQ %d.\n", esp->irq);
                esp_deallocate(esp);
                scsi_unregister(esp->ehost);
                return 0;
            }

             if (request_dma(esp->dma, "NCR 53c9x SCSI")) {
                printk("Unable to request DMA channel %d.\n",
                 esp->dma);
                free_irq(esp->irq, esp_intr);
                esp_deallocate(esp);
                scsi_unregister(esp->ehost);
                return 0;
            }

            request_region(tmp_io_addr, 32, "NCR 53c9x SCSI");

            /*
             * 86C01 handles DMA, IO mode, from address
             *  (base + 0x0a)
             */

            mca_disable_dma(esp->dma);
            mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a);
            mca_enable_dma(esp->dma);
 
            /* Tell the 86C01 to give us interrupts */

            tmp_byte = inb(tmp_io_addr + 0x02) | 0x40;
            outb(tmp_byte, tmp_io_addr + 0x02); 

            /*
             * Scsi ID -- general purpose register, hi
             *  2 bits; add 4 to this number to get the
             *  ID
             */

            esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4;

            /* Do command transfer with programmed I/O */

            esp->do_pio_cmds = 1;

            /* Required functions */

            esp->dma_bytes_sent = &dma_bytes_sent;
            esp->dma_can_transfer = &dma_can_transfer;
            esp->dma_dump_state = &dma_dump_state;
            esp->dma_init_read = &dma_init_read;
            esp->dma_init_write = &dma_init_write;
            esp->dma_ints_off = &dma_ints_off;
            esp->dma_ints_on = &dma_ints_on;
            esp->dma_irq_p = &dma_irq_p;
            esp->dma_ports_p = &dma_ports_p;
            esp->dma_setup = &dma_setup;

            /* Optional functions */

            esp->dma_barrier = 0;
            esp->dma_drain = 0;
            esp->dma_invalidate = 0;
            esp->dma_irq_entry = 0;
            esp->dma_irq_exit = 0;
            esp->dma_led_on = dma_led_on;
            esp->dma_led_off = dma_led_off;
            esp->dma_poll = 0;
            esp->dma_reset = 0;

            /* Set the command buffer */

            esp->esp_command = (volatile unsigned char*)
              cmd_buffer;
             esp->esp_command_dvma = virt_to_bus(cmd_buffer);

            /* SCSI chip speed */

            esp->cfreq = 25000000;

            /* Differential SCSI? I think not. */

            esp->diff = 0;

            esp_initialize(esp);

                  printk(" Adapter found in slot %2d: io port 0x%x "
              "irq %d dma channel %d\n", slot + 1, tmp_io_addr,
               esp->irq, esp->dma);

            mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter");
            mca_mark_as_used(slot);

            break;
        }
    
        id_to_check++;
    }

    return esps_in_use;
}


/******************************************************************* Release */

int mca_esp_release(struct Scsi_Host *host)
{
    struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata;
    unsigned char tmp_byte;

    esp_deallocate(esp);
    /*
     * Tell the 86C01 to stop sending interrupts
     */

    tmp_byte = inb(esp->eregs->io_addr - 0x0E);
    tmp_byte &= ~0x40;
    outb(tmp_byte, esp->eregs->io_addr - 0x0E);

    free_irq(esp->irq, esp_intr);
    free_dma(esp->dma);

    mca_mark_as_unused(esp->slot);

    return 0;
}

/************************************************************* DMA Functions */
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
{
    /* Ask the 53c9x.  It knows. */

    return fifo_count;
}

static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
    /* 
     * The MCA dma channels can only do up to 128K bytes at a time.
         *  (16 bit mode)
     */

    unsigned long sz = sp->SCp.this_residual;
    if(sz > 0x20000)
        sz = 0x20000;
    return sz;
}

static void dma_dump_state(struct NCR_ESP *esp)
{
    /*
     * Doesn't quite match up to the other drivers, but we do what we
     *  can.
     */

    ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma));
    ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma)));
}

static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
{
    unsigned long flags;


    save_flags(flags);
    cli();

    mca_disable_dma(esp->dma);
    mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 |
      MCA_DMA_MODE_IO);
    mca_set_dma_addr(esp->dma, addr);
    mca_set_dma_count(esp->dma, length / 2); /* !!! */
    mca_enable_dma(esp->dma);

    restore_flags(flags);
}

static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
{
    unsigned long flags;


    save_flags(flags);
    cli();

    mca_disable_dma(esp->dma);
    mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE |
      MCA_DMA_MODE_16 | MCA_DMA_MODE_IO);
    mca_set_dma_addr(esp->dma, addr);
    mca_set_dma_count(esp->dma, length / 2); /* !!! */
    mca_enable_dma(esp->dma);

    restore_flags(flags);
}

static void dma_ints_off(struct NCR_ESP *esp)
{
    /*
     * Tell the 'C01 to shut up.  All interrupts are routed through it.
     */

    outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40,
     esp->eregs->io_addr - 0x0E);
}

static void dma_ints_on(struct NCR_ESP *esp)
{
    /*
     * Ok.  You can speak again.
     */

    outb(inb(esp->eregs->io_addr - 0x0E) | 0x40,
     esp->eregs->io_addr - 0x0E);
}

static int dma_irq_p(struct NCR_ESP *esp)
{
    /*
     * DaveM says that this should return a "yes" if there is an interrupt
     *  or a DMA error occurred.  I copied the Amiga driver's semantics,
     *  though, because it seems to work and we can't really tell if
     *  a DMA error happened.  This gives the "yes" if the scsi chip
     *  is sending an interrupt and no DMA activity is taking place
     */

    return (!(inb(esp->eregs->io_addr - 0x04) & 1) &&
     !(inb(esp->eregs->io_addr - 0x04) & 2) ); 
}

static int dma_ports_p(struct NCR_ESP *esp)
{
    /*
     * Check to see if interrupts are enabled on the 'C01 (in case abort
     *  is entered multiple times, so we only do the abort once)
     */

    return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0;
}

static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
{
    if(write){
        dma_init_write(esp, addr, count);
    } else {
        dma_init_read(esp, addr, count);
    }
}

/*
 * These will not play nicely with other disk controllers that try to use the
 *  disk active LED... but what can you do?  Don't answer that.
 *
 * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver
 *
 */

static void dma_led_on(struct NCR_ESP *esp)
{
    outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR);
}

static void dma_led_off(struct NCR_ESP *esp)
{
    outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR);
}

static Scsi_Host_Template driver_template = MCA_53C9X;
#include "scsi_module.c"

/*
 * OK, here's the goods I promised.  The NCR 86C01 is an MCA interface chip 
 *  that handles enabling/diabling IRQ, dma interfacing, IO port selection
 *  and other fun stuff.  It takes up 16 addresses, and the chip it is
 *  connnected to gets the following 16.  Registers are as follows:
 *
 * Offsets 0-1 : Card ID
 *
 * Offset    2 : Mode enable register --
 *                Bit    7 : Data Word width (1 = 16, 0 = 8)
 *          Bit    6 : IRQ enable (1 = enabled)
 *                Bits 5,4 : IRQ select
 *                              0  0 : IRQ 3
 *                    0  1 : IRQ 5
 *                 1  0 : IRQ 7
 *                  1  1 : IRQ 9
 *                Bits 3-1 : Base Address
 *                           0  0  0 : <disabled>
 *                  0  0  1 : 0x0240
 *                     0  1  0 : 0x0340
 *                      0  1  1 : 0x0400
 *                  1  0  0 : 0x0420
 *                  1  0  1 : 0x3240
 *                  1  1  0 : 0x8240
 *                  1  1  1 : 0xA240
 *          Bit    0 : Card enable (1 = enabled)
 *
 * Offset    3 : DMA control register --
 *                Bit    7 : DMA enable (1 = enabled)
 *                Bits 6,5 : Preemt Count Select (transfers to complete after
 *                            'C01 has been preempted on MCA bus)
 *                              0  0 : 0
 *                              0  1 : 1
 *                              1  0 : 3
 *                              1  1 : 7
 *  (all these wacky numbers; I'm sure there's a reason somewhere)
 *                Bit    4 : Fairness enable (1 = fair bus priority)
 *                Bits 3-0 : Arbitration level (0-15 consecutive)
 * 
 * Offset    4 : General purpose register
 *                Bits 7-3 : User definable (here, 7,6 are SCSI ID)
 *                Bits 2-0 : reserved
 *
 * Offset   10 : DMA decode register (used for IO based DMA; also can do
 *                PIO through this port)
 *
 * Offset   12 : Status
 *                Bits 7-2 : reserved
 *                Bit    1 : DMA pending (1 = pending)
 *                Bit    0 : IRQ pending (0 = pending)
 *
 * Exciting, huh?  
 *
 */                

:: 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.01 ]--