forked from Minki/linux
[SCSI] remove m68k NCR53C9x based drivers
These drivers depend on the deprecated NCR53C9X core and need to be converted to the esp_scsi core. Acked-by: Boaz Harrosh <bharrosh@panasas.com> Cc: Linux/m68k <linux-m68k@vger.kernel.org> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
da19d2f532
commit
642978beb4
@ -1578,45 +1578,6 @@ config GVP11_SCSI
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gvp11.
|
||||
|
||||
config CYBERSTORM_SCSI
|
||||
tristate "CyberStorm SCSI support"
|
||||
depends on ZORRO && SCSI
|
||||
help
|
||||
If you have an Amiga with an original (MkI) Phase5 Cyberstorm
|
||||
accelerator board and the optional Cyberstorm SCSI controller,
|
||||
answer Y. Otherwise, say N.
|
||||
|
||||
config CYBERSTORMII_SCSI
|
||||
tristate "CyberStorm Mk II SCSI support"
|
||||
depends on ZORRO && SCSI
|
||||
help
|
||||
If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
|
||||
and the optional Cyberstorm SCSI controller, say Y. Otherwise,
|
||||
answer N.
|
||||
|
||||
config BLZ2060_SCSI
|
||||
tristate "Blizzard 2060 SCSI support"
|
||||
depends on ZORRO && SCSI
|
||||
help
|
||||
If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
|
||||
and want to use the onboard SCSI controller, say Y. Otherwise,
|
||||
answer N.
|
||||
|
||||
config BLZ1230_SCSI
|
||||
tristate "Blizzard 1230IV/1260 SCSI support"
|
||||
depends on ZORRO && SCSI
|
||||
help
|
||||
If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
|
||||
1260 accelerator, and the optional SCSI module, say Y. Otherwise,
|
||||
say N.
|
||||
|
||||
config FASTLANE_SCSI
|
||||
tristate "Fastlane SCSI support"
|
||||
depends on ZORRO && SCSI
|
||||
help
|
||||
If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
|
||||
one in the near future, say Y to this question. Otherwise, say N.
|
||||
|
||||
config SCSI_A4000T
|
||||
tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)"
|
||||
depends on AMIGA && SCSI && EXPERIMENTAL
|
||||
@ -1644,15 +1605,6 @@ config SCSI_ZORRO7XX
|
||||
accelerator card for the Amiga 1200,
|
||||
- the SCSI controller on the GVP Turbo 040/060 accelerator.
|
||||
|
||||
config OKTAGON_SCSI
|
||||
tristate "BSC Oktagon SCSI support (EXPERIMENTAL)"
|
||||
depends on ZORRO && SCSI && EXPERIMENTAL
|
||||
help
|
||||
If you have the BSC Oktagon SCSI disk controller for the Amiga, say
|
||||
Y to this question. If you're in doubt about whether you have one,
|
||||
see the picture at
|
||||
<http://amiga.resource.cx/exp/search.pl?product=oktagon>.
|
||||
|
||||
config ATARI_SCSI
|
||||
tristate "Atari native SCSI support"
|
||||
depends on ATARI && SCSI
|
||||
@ -1705,18 +1657,6 @@ config MAC_SCSI
|
||||
SCSI-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
config SCSI_MAC_ESP
|
||||
tristate "Macintosh NCR53c9[46] SCSI"
|
||||
depends on MAC && SCSI
|
||||
help
|
||||
This is the NCR 53c9x SCSI controller found on most of the 68040
|
||||
based Macintoshes. If you have one of these say Y and read the
|
||||
SCSI-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mac_esp.
|
||||
|
||||
config MVME147_SCSI
|
||||
bool "WD33C93 SCSI driver for MVME147"
|
||||
depends on MVME147 && SCSI=y
|
||||
|
@ -44,15 +44,8 @@ obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
|
||||
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
|
||||
obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
|
||||
obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o
|
||||
obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o
|
||||
obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o
|
||||
obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o
|
||||
obj-$(CONFIG_BLZ1230_SCSI) += NCR53C9x.o blz1230.o
|
||||
obj-$(CONFIG_FASTLANE_SCSI) += NCR53C9x.o fastlane.o
|
||||
obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp_mod.o
|
||||
obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
|
||||
obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
|
||||
obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
|
||||
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
|
||||
obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
|
||||
obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
|
||||
|
@ -1,353 +0,0 @@
|
||||
/* blz1230.c: Driver for Blizzard 1230 SCSI IV Controller.
|
||||
*
|
||||
* Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
|
||||
*
|
||||
* This driver is based on the CyberStorm driver, hence the occasional
|
||||
* reference to CyberStorm.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* 1) Figure out how to make a cleaner merge with the sparc driver with regard
|
||||
* to the caches and the Sparc MMU mapping.
|
||||
* 2) Make as few routines required outside the generic driver. A lot of the
|
||||
* routines in this file used to be inline!
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <linux/zorro.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#define MKIV 1
|
||||
|
||||
/* The controller registers can be found in the Z2 config area at these
|
||||
* offsets:
|
||||
*/
|
||||
#define BLZ1230_ESP_ADDR 0x8000
|
||||
#define BLZ1230_DMA_ADDR 0x10000
|
||||
#define BLZ1230II_ESP_ADDR 0x10000
|
||||
#define BLZ1230II_DMA_ADDR 0x10021
|
||||
|
||||
|
||||
/* The Blizzard 1230 DMA interface
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Only two things can be programmed in the Blizzard DMA:
|
||||
* 1) The data direction is controlled by the status of bit 31 (1 = write)
|
||||
* 2) The source/dest address (word aligned, shifted one right) in bits 30-0
|
||||
*
|
||||
* Program DMA by first latching the highest byte of the address/direction
|
||||
* (i.e. bits 31-24 of the long word constructed as described in steps 1+2
|
||||
* above). Then write each byte of the address/direction (starting with the
|
||||
* top byte, working down) to the DMA address register.
|
||||
*
|
||||
* Figure out interrupt status by reading the ESP status byte.
|
||||
*/
|
||||
struct blz1230_dma_registers {
|
||||
volatile unsigned char dma_addr; /* DMA address [0x0000] */
|
||||
unsigned char dmapad2[0x7fff];
|
||||
volatile unsigned char dma_latch; /* DMA latch [0x8000] */
|
||||
};
|
||||
|
||||
struct blz1230II_dma_registers {
|
||||
volatile unsigned char dma_addr; /* DMA address [0x0000] */
|
||||
unsigned char dmapad2[0xf];
|
||||
volatile unsigned char dma_latch; /* DMA latch [0x0010] */
|
||||
};
|
||||
|
||||
#define BLZ1230_DMA_WRITE 0x80000000
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP *esp);
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_ints_off(struct NCR_ESP *esp);
|
||||
static void dma_ints_on(struct NCR_ESP *esp);
|
||||
static int dma_irq_p(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are transferred to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
/***************************************************************** Detection */
|
||||
int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned long address;
|
||||
struct ESP_regs *eregs;
|
||||
unsigned long board;
|
||||
|
||||
#if MKIV
|
||||
#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260
|
||||
#define REAL_BLZ1230_ESP_ADDR BLZ1230_ESP_ADDR
|
||||
#define REAL_BLZ1230_DMA_ADDR BLZ1230_DMA_ADDR
|
||||
#else
|
||||
#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060
|
||||
#define REAL_BLZ1230_ESP_ADDR BLZ1230II_ESP_ADDR
|
||||
#define REAL_BLZ1230_DMA_ADDR BLZ1230II_DMA_ADDR
|
||||
#endif
|
||||
|
||||
if ((z = zorro_find_device(REAL_BLZ1230_ID, z))) {
|
||||
board = z->resource.start;
|
||||
if (request_mem_region(board+REAL_BLZ1230_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
/* Do some magic to figure out if the blizzard is
|
||||
* equipped with a SCSI controller
|
||||
*/
|
||||
address = ZTWO_VADDR(board);
|
||||
eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
|
||||
0);
|
||||
|
||||
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
|
||||
udelay(5);
|
||||
if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
|
||||
goto err_out;
|
||||
|
||||
/* 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 = 0;
|
||||
esp->dma_led_off = 0;
|
||||
esp->dma_poll = 0;
|
||||
esp->dma_reset = 0;
|
||||
|
||||
/* SCSI chip speed */
|
||||
esp->cfreq = 40000000;
|
||||
|
||||
/* The DMA registers on the Blizzard are mapped
|
||||
* relative to the device (i.e. in the same Zorro
|
||||
* I/O block).
|
||||
*/
|
||||
esp->dregs = (void *)(address + REAL_BLZ1230_DMA_ADDR);
|
||||
|
||||
/* ESP register base */
|
||||
esp->eregs = eregs;
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = cmd_buffer;
|
||||
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
|
||||
|
||||
esp->irq = IRQ_AMIGA_PORTS;
|
||||
esp->slot = board+REAL_BLZ1230_ESP_ADDR;
|
||||
if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
|
||||
"Blizzard 1230 SCSI IV", esp->ehost))
|
||||
goto err_out;
|
||||
|
||||
/* Figure out our scsi ID on the bus */
|
||||
esp->scsi_id = 7;
|
||||
|
||||
/* We don't have a differential SCSI-bus. */
|
||||
esp->diff = 0;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
return esps_in_use;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
scsi_unregister(esp->ehost);
|
||||
esp_deallocate(esp);
|
||||
release_mem_region(board+REAL_BLZ1230_ESP_ADDR,
|
||||
sizeof(struct ESP_regs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
|
||||
{
|
||||
/* Since the Blizzard DMA is fully dedicated to the ESP chip,
|
||||
* the number of bytes sent (to the ESP chip) equals the number
|
||||
* of bytes in the FIFO - there is no buffering in the DMA controller.
|
||||
* XXXX Do I read this right? It is from host to ESP, right?
|
||||
*/
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
/* I don't think there's any limit on the Blizzard DMA. So we use what
|
||||
* the ESP chip can handle (24 bit).
|
||||
*/
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
if(sz > 0x1000000)
|
||||
sz = 0x1000000;
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP *esp)
|
||||
{
|
||||
ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
|
||||
amiga_custom.intreqr, amiga_custom.intenar));
|
||||
}
|
||||
|
||||
void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
#if MKIV
|
||||
struct blz1230_dma_registers *dregs =
|
||||
(struct blz1230_dma_registers *) (esp->dregs);
|
||||
#else
|
||||
struct blz1230II_dma_registers *dregs =
|
||||
(struct blz1230II_dma_registers *) (esp->dregs);
|
||||
#endif
|
||||
|
||||
cache_clear(addr, length);
|
||||
|
||||
addr >>= 1;
|
||||
addr &= ~(BLZ1230_DMA_WRITE);
|
||||
|
||||
/* First set latch */
|
||||
dregs->dma_latch = (addr >> 24) & 0xff;
|
||||
|
||||
/* Then pump the address to the DMA address register */
|
||||
#if MKIV
|
||||
dregs->dma_addr = (addr >> 24) & 0xff;
|
||||
#endif
|
||||
dregs->dma_addr = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr = (addr ) & 0xff;
|
||||
}
|
||||
|
||||
void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
#if MKIV
|
||||
struct blz1230_dma_registers *dregs =
|
||||
(struct blz1230_dma_registers *) (esp->dregs);
|
||||
#else
|
||||
struct blz1230II_dma_registers *dregs =
|
||||
(struct blz1230II_dma_registers *) (esp->dregs);
|
||||
#endif
|
||||
|
||||
cache_push(addr, length);
|
||||
|
||||
addr >>= 1;
|
||||
addr |= BLZ1230_DMA_WRITE;
|
||||
|
||||
/* First set latch */
|
||||
dregs->dma_latch = (addr >> 24) & 0xff;
|
||||
|
||||
/* Then pump the address to the DMA address register */
|
||||
#if MKIV
|
||||
dregs->dma_addr = (addr >> 24) & 0xff;
|
||||
#endif
|
||||
dregs->dma_addr = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr = (addr ) & 0xff;
|
||||
}
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP *esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP *esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
|
||||
}
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return ((amiga_custom.intenar) & IF_PORTS);
|
||||
}
|
||||
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
|
||||
{
|
||||
/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
|
||||
* so when (write) is true, it actually means READ!
|
||||
*/
|
||||
if(write){
|
||||
dma_init_read(esp, addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOSTS_C
|
||||
|
||||
int blz1230_esp_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
|
||||
esp_deallocate((struct NCR_ESP *)instance->hostdata);
|
||||
esp_release();
|
||||
release_mem_region(address, sizeof(struct ESP_regs));
|
||||
free_irq(IRQ_AMIGA_PORTS, esp_intr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "esp-blz1230",
|
||||
.proc_info = esp_proc_info,
|
||||
.name = "Blizzard1230 SCSI IV",
|
||||
.detect = blz1230_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = blz1230_esp_release,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,306 +0,0 @@
|
||||
/* blz2060.c: Driver for Blizzard 2060 SCSI Controller.
|
||||
*
|
||||
* Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
|
||||
*
|
||||
* This driver is based on the CyberStorm driver, hence the occasional
|
||||
* reference to CyberStorm.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* 1) Figure out how to make a cleaner merge with the sparc driver with regard
|
||||
* to the caches and the Sparc MMU mapping.
|
||||
* 2) Make as few routines required outside the generic driver. A lot of the
|
||||
* routines in this file used to be inline!
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <linux/zorro.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/* The controller registers can be found in the Z2 config area at these
|
||||
* offsets:
|
||||
*/
|
||||
#define BLZ2060_ESP_ADDR 0x1ff00
|
||||
#define BLZ2060_DMA_ADDR 0x1ffe0
|
||||
|
||||
|
||||
/* The Blizzard 2060 DMA interface
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Only two things can be programmed in the Blizzard DMA:
|
||||
* 1) The data direction is controlled by the status of bit 31 (1 = write)
|
||||
* 2) The source/dest address (word aligned, shifted one right) in bits 30-0
|
||||
*
|
||||
* Figure out interrupt status by reading the ESP status byte.
|
||||
*/
|
||||
struct blz2060_dma_registers {
|
||||
volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */
|
||||
unsigned char dmapad1[0x0f];
|
||||
volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */
|
||||
unsigned char dmapad2[0x03];
|
||||
volatile unsigned char dma_addr1; /* DMA address [0x014] */
|
||||
unsigned char dmapad3[0x03];
|
||||
volatile unsigned char dma_addr2; /* DMA address [0x018] */
|
||||
unsigned char dmapad4[0x03];
|
||||
volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */
|
||||
};
|
||||
|
||||
#define BLZ2060_DMA_WRITE 0x80000000
|
||||
|
||||
/* DMA control bits */
|
||||
#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP *esp);
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_ints_off(struct NCR_ESP *esp);
|
||||
static void dma_ints_on(struct NCR_ESP *esp);
|
||||
static int dma_irq_p(struct NCR_ESP *esp);
|
||||
static void dma_led_off(struct NCR_ESP *esp);
|
||||
static void dma_led_on(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are transferred to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
/***************************************************************** Detection */
|
||||
int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned long address;
|
||||
|
||||
if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_2060, z))) {
|
||||
unsigned long board = z->resource.start;
|
||||
if (request_mem_region(board+BLZ2060_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* SCSI chip speed */
|
||||
esp->cfreq = 40000000;
|
||||
|
||||
/* The DMA registers on the Blizzard are mapped
|
||||
* relative to the device (i.e. in the same Zorro
|
||||
* I/O block).
|
||||
*/
|
||||
address = (unsigned long)ZTWO_VADDR(board);
|
||||
esp->dregs = (void *)(address + BLZ2060_DMA_ADDR);
|
||||
|
||||
/* ESP register base */
|
||||
esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = cmd_buffer;
|
||||
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
|
||||
|
||||
esp->irq = IRQ_AMIGA_PORTS;
|
||||
request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
|
||||
"Blizzard 2060 SCSI", esp->ehost);
|
||||
|
||||
/* Figure out our scsi ID on the bus */
|
||||
esp->scsi_id = 7;
|
||||
|
||||
/* We don't have a differential SCSI-bus. */
|
||||
esp->diff = 0;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
return esps_in_use;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
|
||||
{
|
||||
/* Since the Blizzard DMA is fully dedicated to the ESP chip,
|
||||
* the number of bytes sent (to the ESP chip) equals the number
|
||||
* of bytes in the FIFO - there is no buffering in the DMA controller.
|
||||
* XXXX Do I read this right? It is from host to ESP, right?
|
||||
*/
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
/* I don't think there's any limit on the Blizzard DMA. So we use what
|
||||
* the ESP chip can handle (24 bit).
|
||||
*/
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
if(sz > 0x1000000)
|
||||
sz = 0x1000000;
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP *esp)
|
||||
{
|
||||
ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
|
||||
amiga_custom.intreqr, amiga_custom.intenar));
|
||||
}
|
||||
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct blz2060_dma_registers *dregs =
|
||||
(struct blz2060_dma_registers *) (esp->dregs);
|
||||
|
||||
cache_clear(addr, length);
|
||||
|
||||
addr >>= 1;
|
||||
addr &= ~(BLZ2060_DMA_WRITE);
|
||||
dregs->dma_addr3 = (addr ) & 0xff;
|
||||
dregs->dma_addr2 = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr1 = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr0 = (addr >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct blz2060_dma_registers *dregs =
|
||||
(struct blz2060_dma_registers *) (esp->dregs);
|
||||
|
||||
cache_push(addr, length);
|
||||
|
||||
addr >>= 1;
|
||||
addr |= BLZ2060_DMA_WRITE;
|
||||
dregs->dma_addr3 = (addr ) & 0xff;
|
||||
dregs->dma_addr2 = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr1 = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr0 = (addr >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP *esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP *esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
|
||||
}
|
||||
|
||||
static void dma_led_off(struct NCR_ESP *esp)
|
||||
{
|
||||
((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl =
|
||||
BLZ2060_DMA_LED;
|
||||
}
|
||||
|
||||
static void dma_led_on(struct NCR_ESP *esp)
|
||||
{
|
||||
((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = 0;
|
||||
}
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return ((amiga_custom.intenar) & IF_PORTS);
|
||||
}
|
||||
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
|
||||
{
|
||||
/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
|
||||
* so when (write) is true, it actually means READ!
|
||||
*/
|
||||
if(write){
|
||||
dma_init_read(esp, addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOSTS_C
|
||||
|
||||
int blz2060_esp_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
|
||||
|
||||
esp_deallocate((struct NCR_ESP *)instance->hostdata);
|
||||
esp_release();
|
||||
release_mem_region(address, sizeof(struct ESP_regs));
|
||||
free_irq(IRQ_AMIGA_PORTS, esp_intr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "esp-blz2060",
|
||||
.proc_info = esp_proc_info,
|
||||
.name = "Blizzard2060 SCSI",
|
||||
.detect = blz2060_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = blz2060_esp_release,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,377 +0,0 @@
|
||||
/* cyberstorm.c: Driver for CyberStorm SCSI Controller.
|
||||
*
|
||||
* Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
|
||||
*
|
||||
* The CyberStorm SCSI driver is based on David S. Miller's ESP driver
|
||||
* for the Sparc computers.
|
||||
*
|
||||
* This work was made possible by Phase5 who willingly (and most generously)
|
||||
* supported me with hardware and all the information I needed.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* 1) Figure out how to make a cleaner merge with the sparc driver with regard
|
||||
* to the caches and the Sparc MMU mapping.
|
||||
* 2) Make as few routines required outside the generic driver. A lot of the
|
||||
* routines in this file used to be inline!
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <linux/zorro.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/* The controller registers can be found in the Z2 config area at these
|
||||
* offsets:
|
||||
*/
|
||||
#define CYBER_ESP_ADDR 0xf400
|
||||
#define CYBER_DMA_ADDR 0xf800
|
||||
|
||||
|
||||
/* The CyberStorm DMA interface */
|
||||
struct cyber_dma_registers {
|
||||
volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */
|
||||
unsigned char dmapad1[1];
|
||||
volatile unsigned char dma_addr1; /* DMA address [0x002] */
|
||||
unsigned char dmapad2[1];
|
||||
volatile unsigned char dma_addr2; /* DMA address [0x004] */
|
||||
unsigned char dmapad3[1];
|
||||
volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */
|
||||
unsigned char dmapad4[0x3fb];
|
||||
volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */
|
||||
#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */
|
||||
};
|
||||
|
||||
/* DMA control bits */
|
||||
#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */
|
||||
#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */
|
||||
#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
|
||||
|
||||
/* DMA status bits */
|
||||
#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */
|
||||
|
||||
/* The bits below appears to be Phase5 Debug bits only; they were not
|
||||
* described by Phase5 so using them may seem a bit stupid...
|
||||
*/
|
||||
#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise
|
||||
* it should be 6.
|
||||
*/
|
||||
#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP *esp);
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_ints_off(struct NCR_ESP *esp);
|
||||
static void dma_ints_on(struct NCR_ESP *esp);
|
||||
static int dma_irq_p(struct NCR_ESP *esp);
|
||||
static void dma_led_off(struct NCR_ESP *esp);
|
||||
static void dma_led_on(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
|
||||
|
||||
static unsigned char ctrl_data = 0; /* Keep backup of the stuff written
|
||||
* to ctrl_reg. Always write a copy
|
||||
* to this register when writing to
|
||||
* the hardware register!
|
||||
*/
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are transferred to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
/***************************************************************** Detection */
|
||||
int __init cyber_esp_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned long address;
|
||||
|
||||
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
|
||||
unsigned long board = z->resource.start;
|
||||
if ((z->id == ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM ||
|
||||
z->id == ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) &&
|
||||
request_mem_region(board+CYBER_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
/* Figure out if this is a CyberStorm or really a
|
||||
* Fastlane/Blizzard Mk II by looking at the board size.
|
||||
* CyberStorm maps 64kB
|
||||
* (ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM does anyway)
|
||||
*/
|
||||
if(z->resource.end-board != 0xffff) {
|
||||
release_mem_region(board+CYBER_ESP_ADDR,
|
||||
sizeof(struct ESP_regs));
|
||||
return 0;
|
||||
}
|
||||
esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* SCSI chip speed */
|
||||
esp->cfreq = 40000000;
|
||||
|
||||
/* The DMA registers on the CyberStorm are mapped
|
||||
* relative to the device (i.e. in the same Zorro
|
||||
* I/O block).
|
||||
*/
|
||||
address = (unsigned long)ZTWO_VADDR(board);
|
||||
esp->dregs = (void *)(address + CYBER_DMA_ADDR);
|
||||
|
||||
/* ESP register base */
|
||||
esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = cmd_buffer;
|
||||
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
|
||||
|
||||
esp->irq = IRQ_AMIGA_PORTS;
|
||||
request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
|
||||
"CyberStorm SCSI", esp->ehost);
|
||||
/* Figure out our scsi ID on the bus */
|
||||
/* The DMA cond flag contains a hardcoded jumper bit
|
||||
* which can be used to select host number 6 or 7.
|
||||
* However, even though it may change, we use a hardcoded
|
||||
* value of 7.
|
||||
*/
|
||||
esp->scsi_id = 7;
|
||||
|
||||
/* We don't have a differential SCSI-bus. */
|
||||
esp->diff = 0;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
return esps_in_use;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
|
||||
{
|
||||
/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
|
||||
* the number of bytes sent (to the ESP chip) equals the number
|
||||
* of bytes in the FIFO - there is no buffering in the DMA controller.
|
||||
* XXXX Do I read this right? It is from host to ESP, right?
|
||||
*/
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
/* I don't think there's any limit on the CyberDMA. So we use what
|
||||
* the ESP chip can handle (24 bit).
|
||||
*/
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
if(sz > 0x1000000)
|
||||
sz = 0x1000000;
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP *esp)
|
||||
{
|
||||
ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
|
||||
esp->esp_id, ((struct cyber_dma_registers *)
|
||||
(esp->dregs))->cond_reg));
|
||||
ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
|
||||
amiga_custom.intreqr, amiga_custom.intenar));
|
||||
}
|
||||
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct cyber_dma_registers *dregs =
|
||||
(struct cyber_dma_registers *) esp->dregs;
|
||||
|
||||
cache_clear(addr, length);
|
||||
|
||||
addr &= ~(1);
|
||||
dregs->dma_addr0 = (addr >> 24) & 0xff;
|
||||
dregs->dma_addr1 = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr2 = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr3 = (addr ) & 0xff;
|
||||
ctrl_data &= ~(CYBER_DMA_WRITE);
|
||||
|
||||
/* Check if physical address is outside Z2 space and of
|
||||
* block length/block aligned in memory. If this is the
|
||||
* case, enable 32 bit transfer. In all other cases, fall back
|
||||
* to 16 bit transfer.
|
||||
* Obviously 32 bit transfer should be enabled if the DMA address
|
||||
* and length are 32 bit aligned. However, this leads to some
|
||||
* strange behavior. Even 64 bit aligned addr/length fails.
|
||||
* Until I've found a reason for this, 32 bit transfer is only
|
||||
* used for full-block transfers (1kB).
|
||||
* -jskov
|
||||
*/
|
||||
#if 0
|
||||
if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) &&
|
||||
(addr < 0xff0000)))
|
||||
ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
|
||||
else
|
||||
ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */
|
||||
#else
|
||||
ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
|
||||
#endif
|
||||
dregs->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct cyber_dma_registers *dregs =
|
||||
(struct cyber_dma_registers *) esp->dregs;
|
||||
|
||||
cache_push(addr, length);
|
||||
|
||||
addr |= 1;
|
||||
dregs->dma_addr0 = (addr >> 24) & 0xff;
|
||||
dregs->dma_addr1 = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr2 = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr3 = (addr ) & 0xff;
|
||||
ctrl_data |= CYBER_DMA_WRITE;
|
||||
|
||||
/* See comment above */
|
||||
#if 0
|
||||
if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) &&
|
||||
(addr < 0xff0000)))
|
||||
ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
|
||||
else
|
||||
ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */
|
||||
#else
|
||||
ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */
|
||||
#endif
|
||||
dregs->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP *esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP *esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP *esp)
|
||||
{
|
||||
/* It's important to check the DMA IRQ bit in the correct way! */
|
||||
return ((esp_read(esp->eregs->esp_status) & ESP_STAT_INTR) &&
|
||||
((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) &
|
||||
CYBER_DMA_HNDL_INTR));
|
||||
}
|
||||
|
||||
static void dma_led_off(struct NCR_ESP *esp)
|
||||
{
|
||||
ctrl_data &= ~CYBER_DMA_LED;
|
||||
((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static void dma_led_on(struct NCR_ESP *esp)
|
||||
{
|
||||
ctrl_data |= CYBER_DMA_LED;
|
||||
((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return ((amiga_custom.intenar) & IF_PORTS);
|
||||
}
|
||||
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
|
||||
{
|
||||
/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
|
||||
* so when (write) is true, it actually means READ!
|
||||
*/
|
||||
if(write){
|
||||
dma_init_read(esp, addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOSTS_C
|
||||
|
||||
int cyber_esp_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
|
||||
|
||||
esp_deallocate((struct NCR_ESP *)instance->hostdata);
|
||||
esp_release();
|
||||
release_mem_region(address, sizeof(struct ESP_regs));
|
||||
free_irq(IRQ_AMIGA_PORTS, esp_intr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "esp-cyberstorm",
|
||||
.proc_info = esp_proc_info,
|
||||
.name = "CyberStorm SCSI",
|
||||
.detect = cyber_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = cyber_esp_release,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,314 +0,0 @@
|
||||
/* cyberstormII.c: Driver for CyberStorm SCSI Mk II
|
||||
*
|
||||
* Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
|
||||
*
|
||||
* This driver is based on cyberstorm.c
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* 1) Figure out how to make a cleaner merge with the sparc driver with regard
|
||||
* to the caches and the Sparc MMU mapping.
|
||||
* 2) Make as few routines required outside the generic driver. A lot of the
|
||||
* routines in this file used to be inline!
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <linux/zorro.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/* The controller registers can be found in the Z2 config area at these
|
||||
* offsets:
|
||||
*/
|
||||
#define CYBERII_ESP_ADDR 0x1ff03
|
||||
#define CYBERII_DMA_ADDR 0x1ff43
|
||||
|
||||
|
||||
/* The CyberStorm II DMA interface */
|
||||
struct cyberII_dma_registers {
|
||||
volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */
|
||||
#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */
|
||||
unsigned char dmapad4[0x3f];
|
||||
volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */
|
||||
unsigned char dmapad1[3];
|
||||
volatile unsigned char dma_addr1; /* DMA address [0x044] */
|
||||
unsigned char dmapad2[3];
|
||||
volatile unsigned char dma_addr2; /* DMA address [0x048] */
|
||||
unsigned char dmapad3[3];
|
||||
volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */
|
||||
};
|
||||
|
||||
/* DMA control bits */
|
||||
#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP *esp);
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_ints_off(struct NCR_ESP *esp);
|
||||
static void dma_ints_on(struct NCR_ESP *esp);
|
||||
static int dma_irq_p(struct NCR_ESP *esp);
|
||||
static void dma_led_off(struct NCR_ESP *esp);
|
||||
static void dma_led_on(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are transferred to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
/***************************************************************** Detection */
|
||||
int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned long address;
|
||||
struct ESP_regs *eregs;
|
||||
|
||||
if ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERSTORM_MK_II, z))) {
|
||||
unsigned long board = z->resource.start;
|
||||
if (request_mem_region(board+CYBERII_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
/* Do some magic to figure out if the CyberStorm Mk II
|
||||
* is equipped with a SCSI controller
|
||||
*/
|
||||
address = (unsigned long)ZTWO_VADDR(board);
|
||||
eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
|
||||
|
||||
esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
|
||||
|
||||
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
|
||||
udelay(5);
|
||||
if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) {
|
||||
esp_deallocate(esp);
|
||||
scsi_unregister(esp->ehost);
|
||||
release_mem_region(board+CYBERII_ESP_ADDR,
|
||||
sizeof(struct ESP_regs));
|
||||
return 0; /* Bail out if address did not hold data */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* SCSI chip speed */
|
||||
esp->cfreq = 40000000;
|
||||
|
||||
/* The DMA registers on the CyberStorm are mapped
|
||||
* relative to the device (i.e. in the same Zorro
|
||||
* I/O block).
|
||||
*/
|
||||
esp->dregs = (void *)(address + CYBERII_DMA_ADDR);
|
||||
|
||||
/* ESP register base */
|
||||
esp->eregs = eregs;
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = cmd_buffer;
|
||||
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
|
||||
|
||||
esp->irq = IRQ_AMIGA_PORTS;
|
||||
request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
|
||||
"CyberStorm SCSI Mk II", esp->ehost);
|
||||
|
||||
/* Figure out our scsi ID on the bus */
|
||||
esp->scsi_id = 7;
|
||||
|
||||
/* We don't have a differential SCSI-bus. */
|
||||
esp->diff = 0;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
return esps_in_use;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
|
||||
{
|
||||
/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
|
||||
* the number of bytes sent (to the ESP chip) equals the number
|
||||
* of bytes in the FIFO - there is no buffering in the DMA controller.
|
||||
* XXXX Do I read this right? It is from host to ESP, right?
|
||||
*/
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
/* I don't think there's any limit on the CyberDMA. So we use what
|
||||
* the ESP chip can handle (24 bit).
|
||||
*/
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
if(sz > 0x1000000)
|
||||
sz = 0x1000000;
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP *esp)
|
||||
{
|
||||
ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
|
||||
esp->esp_id, ((struct cyberII_dma_registers *)
|
||||
(esp->dregs))->cond_reg));
|
||||
ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
|
||||
amiga_custom.intreqr, amiga_custom.intenar));
|
||||
}
|
||||
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct cyberII_dma_registers *dregs =
|
||||
(struct cyberII_dma_registers *) esp->dregs;
|
||||
|
||||
cache_clear(addr, length);
|
||||
|
||||
addr &= ~(1);
|
||||
dregs->dma_addr0 = (addr >> 24) & 0xff;
|
||||
dregs->dma_addr1 = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr2 = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr3 = (addr ) & 0xff;
|
||||
}
|
||||
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct cyberII_dma_registers *dregs =
|
||||
(struct cyberII_dma_registers *) esp->dregs;
|
||||
|
||||
cache_push(addr, length);
|
||||
|
||||
addr |= 1;
|
||||
dregs->dma_addr0 = (addr >> 24) & 0xff;
|
||||
dregs->dma_addr1 = (addr >> 16) & 0xff;
|
||||
dregs->dma_addr2 = (addr >> 8) & 0xff;
|
||||
dregs->dma_addr3 = (addr ) & 0xff;
|
||||
}
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP *esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP *esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP *esp)
|
||||
{
|
||||
/* It's important to check the DMA IRQ bit in the correct way! */
|
||||
return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
|
||||
}
|
||||
|
||||
static void dma_led_off(struct NCR_ESP *esp)
|
||||
{
|
||||
((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg &= ~CYBERII_DMA_LED;
|
||||
}
|
||||
|
||||
static void dma_led_on(struct NCR_ESP *esp)
|
||||
{
|
||||
((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg |= CYBERII_DMA_LED;
|
||||
}
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return ((amiga_custom.intenar) & IF_PORTS);
|
||||
}
|
||||
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
|
||||
{
|
||||
/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
|
||||
* so when (write) is true, it actually means READ!
|
||||
*/
|
||||
if(write){
|
||||
dma_init_read(esp, addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOSTS_C
|
||||
|
||||
int cyberII_esp_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
|
||||
|
||||
esp_deallocate((struct NCR_ESP *)instance->hostdata);
|
||||
esp_release();
|
||||
release_mem_region(address, sizeof(struct ESP_regs));
|
||||
free_irq(IRQ_AMIGA_PORTS, esp_intr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "esp-cyberstormII",
|
||||
.proc_info = esp_proc_info,
|
||||
.name = "CyberStorm Mk II SCSI",
|
||||
.detect = cyberII_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = cyberII_esp_release,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,421 +0,0 @@
|
||||
/* fastlane.c: Driver for Phase5's Fastlane SCSI Controller.
|
||||
*
|
||||
* Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
|
||||
*
|
||||
* This driver is based on the CyberStorm driver, hence the occasional
|
||||
* reference to CyberStorm.
|
||||
*
|
||||
* Betatesting & crucial adjustments by
|
||||
* Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
|
||||
*
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* o According to the doc from laire, it is required to reset the DMA when
|
||||
* the transfer is done. ATM we reset DMA just before every new
|
||||
* dma_init_(read|write).
|
||||
*
|
||||
* 1) Figure out how to make a cleaner merge with the sparc driver with regard
|
||||
* to the caches and the Sparc MMU mapping.
|
||||
* 2) Make as few routines required outside the generic driver. A lot of the
|
||||
* routines in this file used to be inline!
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <linux/zorro.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/* Such day has just come... */
|
||||
#if 0
|
||||
/* Let this defined unless you really need to enable DMA IRQ one day */
|
||||
#define NODMAIRQ
|
||||
#endif
|
||||
|
||||
/* The controller registers can be found in the Z2 config area at these
|
||||
* offsets:
|
||||
*/
|
||||
#define FASTLANE_ESP_ADDR 0x1000001
|
||||
#define FASTLANE_DMA_ADDR 0x1000041
|
||||
|
||||
|
||||
/* The Fastlane DMA interface */
|
||||
struct fastlane_dma_registers {
|
||||
volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */
|
||||
#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */
|
||||
unsigned char dmapad1[0x3f];
|
||||
volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */
|
||||
};
|
||||
|
||||
|
||||
/* DMA status bits */
|
||||
#define FASTLANE_DMA_MINT 0x80
|
||||
#define FASTLANE_DMA_IACT 0x40
|
||||
#define FASTLANE_DMA_CREQ 0x20
|
||||
|
||||
/* DMA control bits */
|
||||
#define FASTLANE_DMA_FCODE 0xa0
|
||||
#define FASTLANE_DMA_MASK 0xf3
|
||||
#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */
|
||||
#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */
|
||||
#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */
|
||||
#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */
|
||||
#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP *esp);
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length);
|
||||
static void dma_ints_off(struct NCR_ESP *esp);
|
||||
static void dma_ints_on(struct NCR_ESP *esp);
|
||||
static int dma_irq_p(struct NCR_ESP *esp);
|
||||
static void dma_irq_exit(struct NCR_ESP *esp);
|
||||
static void dma_led_off(struct NCR_ESP *esp);
|
||||
static void dma_led_on(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
|
||||
|
||||
static unsigned char ctrl_data = 0; /* Keep backup of the stuff written
|
||||
* to ctrl_reg. Always write a copy
|
||||
* to this register when writing to
|
||||
* the hardware register!
|
||||
*/
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are transferred to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
static inline void dma_clear(struct NCR_ESP *esp)
|
||||
{
|
||||
struct fastlane_dma_registers *dregs =
|
||||
(struct fastlane_dma_registers *) (esp->dregs);
|
||||
unsigned long *t;
|
||||
|
||||
ctrl_data = (ctrl_data & FASTLANE_DMA_MASK);
|
||||
dregs->ctrl_reg = ctrl_data;
|
||||
|
||||
t = (unsigned long *)(esp->edev);
|
||||
|
||||
dregs->clear_strobe = 0;
|
||||
*t = 0 ;
|
||||
}
|
||||
|
||||
/***************************************************************** Detection */
|
||||
int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned long address;
|
||||
|
||||
if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060, z))) {
|
||||
unsigned long board = z->resource.start;
|
||||
if (request_mem_region(board+FASTLANE_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
/* Check if this is really a fastlane controller. The problem
|
||||
* is that also the cyberstorm and blizzard controllers use
|
||||
* this ID value. Fortunately only Fastlane maps in Z3 space
|
||||
*/
|
||||
if (board < 0x1000000) {
|
||||
goto err_release;
|
||||
}
|
||||
esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
|
||||
|
||||
/* 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 = &dma_irq_exit;
|
||||
esp->dma_led_on = &dma_led_on;
|
||||
esp->dma_led_off = &dma_led_off;
|
||||
esp->dma_poll = 0;
|
||||
esp->dma_reset = 0;
|
||||
|
||||
/* Initialize the portBits (enable IRQs) */
|
||||
ctrl_data = (FASTLANE_DMA_FCODE |
|
||||
#ifndef NODMAIRQ
|
||||
FASTLANE_DMA_EDI |
|
||||
#endif
|
||||
FASTLANE_DMA_ESI);
|
||||
|
||||
|
||||
/* SCSI chip clock */
|
||||
esp->cfreq = 40000000;
|
||||
|
||||
|
||||
/* Map the physical address space into virtual kernel space */
|
||||
address = (unsigned long)
|
||||
z_ioremap(board, z->resource.end-board+1);
|
||||
|
||||
if(!address){
|
||||
printk("Could not remap Fastlane controller memory!");
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
|
||||
/* The DMA registers on the Fastlane are mapped
|
||||
* relative to the device (i.e. in the same Zorro
|
||||
* I/O block).
|
||||
*/
|
||||
esp->dregs = (void *)(address + FASTLANE_DMA_ADDR);
|
||||
|
||||
/* ESP register base */
|
||||
esp->eregs = (struct ESP_regs *)(address + FASTLANE_ESP_ADDR);
|
||||
|
||||
/* Board base */
|
||||
esp->edev = (void *) address;
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = cmd_buffer;
|
||||
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
|
||||
|
||||
esp->irq = IRQ_AMIGA_PORTS;
|
||||
esp->slot = board+FASTLANE_ESP_ADDR;
|
||||
if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
|
||||
"Fastlane SCSI", esp->ehost)) {
|
||||
printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
/* Controller ID */
|
||||
esp->scsi_id = 7;
|
||||
|
||||
/* We don't have a differential SCSI-bus. */
|
||||
esp->diff = 0;
|
||||
|
||||
dma_clear(esp);
|
||||
esp_initialize(esp);
|
||||
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
return esps_in_use;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
z_iounmap((void *)address);
|
||||
err_unregister:
|
||||
scsi_unregister (esp->ehost);
|
||||
err_release:
|
||||
release_mem_region(z->resource.start+FASTLANE_ESP_ADDR,
|
||||
sizeof(struct ESP_regs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
|
||||
{
|
||||
/* Since the Fastlane DMA is fully dedicated to the ESP chip,
|
||||
* the number of bytes sent (to the ESP chip) equals the number
|
||||
* of bytes in the FIFO - there is no buffering in the DMA controller.
|
||||
* XXXX Do I read this right? It is from host to ESP, right?
|
||||
*/
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
if(sz > 0xfffc)
|
||||
sz = 0xfffc;
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP *esp)
|
||||
{
|
||||
ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
|
||||
esp->esp_id, ((struct fastlane_dma_registers *)
|
||||
(esp->dregs))->cond_reg));
|
||||
ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
|
||||
amiga_custom.intreqr, amiga_custom.intenar));
|
||||
}
|
||||
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct fastlane_dma_registers *dregs =
|
||||
(struct fastlane_dma_registers *) (esp->dregs);
|
||||
unsigned long *t;
|
||||
|
||||
cache_clear(addr, length);
|
||||
|
||||
dma_clear(esp);
|
||||
|
||||
t = (unsigned long *)((addr & 0x00ffffff) + esp->edev);
|
||||
|
||||
dregs->clear_strobe = 0;
|
||||
*t = addr;
|
||||
|
||||
ctrl_data = (ctrl_data & FASTLANE_DMA_MASK) | FASTLANE_DMA_ENABLE;
|
||||
dregs->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
|
||||
{
|
||||
struct fastlane_dma_registers *dregs =
|
||||
(struct fastlane_dma_registers *) (esp->dregs);
|
||||
unsigned long *t;
|
||||
|
||||
cache_push(addr, length);
|
||||
|
||||
dma_clear(esp);
|
||||
|
||||
t = (unsigned long *)((addr & 0x00ffffff) + (esp->edev));
|
||||
|
||||
dregs->clear_strobe = 0;
|
||||
*t = addr;
|
||||
|
||||
ctrl_data = ((ctrl_data & FASTLANE_DMA_MASK) |
|
||||
FASTLANE_DMA_ENABLE |
|
||||
FASTLANE_DMA_WRITE);
|
||||
dregs->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP *esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP *esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_irq_exit(struct NCR_ESP *esp)
|
||||
{
|
||||
struct fastlane_dma_registers *dregs =
|
||||
(struct fastlane_dma_registers *) (esp->dregs);
|
||||
|
||||
dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
|
||||
#ifdef __mc68000__
|
||||
nop();
|
||||
#endif
|
||||
dregs->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP *esp)
|
||||
{
|
||||
struct fastlane_dma_registers *dregs =
|
||||
(struct fastlane_dma_registers *) (esp->dregs);
|
||||
unsigned char dma_status;
|
||||
|
||||
dma_status = dregs->cond_reg;
|
||||
|
||||
if(dma_status & FASTLANE_DMA_IACT)
|
||||
return 0; /* not our IRQ */
|
||||
|
||||
/* Return non-zero if ESP requested IRQ */
|
||||
return (
|
||||
#ifndef NODMAIRQ
|
||||
(dma_status & FASTLANE_DMA_CREQ) &&
|
||||
#endif
|
||||
(!(dma_status & FASTLANE_DMA_MINT)) &&
|
||||
(esp_read(((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR));
|
||||
}
|
||||
|
||||
static void dma_led_off(struct NCR_ESP *esp)
|
||||
{
|
||||
ctrl_data &= ~FASTLANE_DMA_LED;
|
||||
((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static void dma_led_on(struct NCR_ESP *esp)
|
||||
{
|
||||
ctrl_data |= FASTLANE_DMA_LED;
|
||||
((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
|
||||
}
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return ((amiga_custom.intenar) & IF_PORTS);
|
||||
}
|
||||
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
|
||||
{
|
||||
/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
|
||||
* so when (write) is true, it actually means READ!
|
||||
*/
|
||||
if(write){
|
||||
dma_init_read(esp, addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOSTS_C
|
||||
|
||||
int fastlane_esp_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
|
||||
esp_deallocate((struct NCR_ESP *)instance->hostdata);
|
||||
esp_release();
|
||||
release_mem_region(address, sizeof(struct ESP_regs));
|
||||
free_irq(IRQ_AMIGA_PORTS, esp_intr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "esp-fastlane",
|
||||
.proc_info = esp_proc_info,
|
||||
.name = "Fastlane SCSI",
|
||||
.detect = fastlane_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = fastlane_esp_release,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING
|
||||
};
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,751 +0,0 @@
|
||||
/*
|
||||
* 68k mac 53c9[46] scsi driver
|
||||
*
|
||||
* copyright (c) 1998, David Weis weisd3458@uni.edu
|
||||
*
|
||||
* debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98
|
||||
*
|
||||
* based loosely on cyber_esp.c
|
||||
*/
|
||||
|
||||
/* these are unused for now */
|
||||
#define myreadl(addr) (*(volatile unsigned int *) (addr))
|
||||
#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b))
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/macints.h>
|
||||
#include <asm/machw.h>
|
||||
#include <asm/mac_via.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include <asm/macintosh.h>
|
||||
|
||||
/* #define DEBUG_MAC_ESP */
|
||||
|
||||
extern void esp_handle(struct NCR_ESP *esp);
|
||||
extern void mac_esp_intr(int irq, void *dev_id);
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP * esp);
|
||||
static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length);
|
||||
static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length);
|
||||
static void dma_ints_off(struct NCR_ESP * esp);
|
||||
static void dma_ints_on(struct NCR_ESP * esp);
|
||||
static int dma_irq_p(struct NCR_ESP * esp);
|
||||
static int dma_irq_p_quick(struct NCR_ESP * esp);
|
||||
static void dma_led_off(struct NCR_ESP * esp);
|
||||
static void dma_led_on(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write);
|
||||
static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write);
|
||||
|
||||
static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev);
|
||||
static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev);
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are transferred to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
static int esp_initialized = 0;
|
||||
|
||||
static int setup_num_esps = -1;
|
||||
static int setup_disconnect = -1;
|
||||
static int setup_nosync = -1;
|
||||
static int setup_can_queue = -1;
|
||||
static int setup_cmd_per_lun = -1;
|
||||
static int setup_sg_tablesize = -1;
|
||||
#ifdef SUPPORT_TAGS
|
||||
static int setup_use_tagged_queuing = -1;
|
||||
#endif
|
||||
static int setup_hostid = -1;
|
||||
|
||||
/*
|
||||
* Experimental ESP inthandler; check macints.c to make sure dev_id is
|
||||
* set up properly!
|
||||
*/
|
||||
|
||||
void mac_esp_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
|
||||
int irq_p = 0;
|
||||
|
||||
/* Handle the one ESP interrupt showing at this IRQ level. */
|
||||
if(((esp)->irq & 0xff) == irq) {
|
||||
/*
|
||||
* Debug ..
|
||||
*/
|
||||
irq_p = esp->dma_irq_p(esp);
|
||||
printk("mac_esp: irq_p %x current %p disconnected %p\n",
|
||||
irq_p, esp->current_SC, esp->disconnected_SC);
|
||||
|
||||
/*
|
||||
* Mac: if we're here, it's an ESP interrupt for sure!
|
||||
*/
|
||||
if((esp->current_SC || esp->disconnected_SC)) {
|
||||
esp->dma_ints_off(esp);
|
||||
|
||||
ESPIRQ(("I%d(", esp->esp_id));
|
||||
esp_handle(esp);
|
||||
ESPIRQ((")"));
|
||||
|
||||
esp->dma_ints_on(esp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug hooks; use for playing with the interrupt flag testing and interrupt
|
||||
* acknowledge on the various machines
|
||||
*/
|
||||
|
||||
void scsi_esp_polled(int irq, void *dev_id)
|
||||
{
|
||||
if (esp_initialized == 0)
|
||||
return;
|
||||
|
||||
mac_esp_intr(irq, dev_id);
|
||||
}
|
||||
|
||||
void fake_intr(int irq, void *dev_id)
|
||||
{
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: got irq\n");
|
||||
#endif
|
||||
|
||||
mac_esp_intr(irq, dev_id);
|
||||
}
|
||||
|
||||
irqreturn_t fake_drq(int irq, void *dev_id)
|
||||
{
|
||||
printk("mac_esp: got drq\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define DRIVER_SETUP
|
||||
|
||||
/*
|
||||
* Function : mac_esp_setup(char *str)
|
||||
*
|
||||
* Purpose : booter command line initialization of the overrides array,
|
||||
*
|
||||
* Inputs : str - parameters, separated by commas.
|
||||
*
|
||||
* Currently unused in the new driver; need to add settable parameters to the
|
||||
* detect function.
|
||||
*
|
||||
*/
|
||||
|
||||
static int __init mac_esp_setup(char *str) {
|
||||
#ifdef DRIVER_SETUP
|
||||
/* Format of mac53c9x parameter is:
|
||||
* mac53c9x=<num_esps>,<disconnect>,<nosync>,<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
|
||||
* Negative values mean don't change.
|
||||
*/
|
||||
|
||||
char *this_opt;
|
||||
long opt;
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
if (opt >= 0 && opt <= 2)
|
||||
setup_num_esps = opt;
|
||||
else if (opt > 2)
|
||||
printk( "mac_esp_setup: invalid number of hosts %ld !\n", opt );
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
if (opt > 0)
|
||||
setup_disconnect = opt;
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
if (opt >= 0)
|
||||
setup_nosync = opt;
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
if (opt > 0)
|
||||
setup_can_queue = opt;
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
if (opt > 0)
|
||||
setup_cmd_per_lun = opt;
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
if (opt >= 0) {
|
||||
setup_sg_tablesize = opt;
|
||||
/* Must be <= SG_ALL (255) */
|
||||
if (setup_sg_tablesize > SG_ALL)
|
||||
setup_sg_tablesize = SG_ALL;
|
||||
}
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
|
||||
/* Must be between 0 and 7 */
|
||||
if (opt >= 0 && opt <= 7)
|
||||
setup_hostid = opt;
|
||||
else if (opt > 7)
|
||||
printk( "mac_esp_setup: invalid host ID %ld !\n", opt);
|
||||
|
||||
this_opt = strsep (&str, ",");
|
||||
}
|
||||
#ifdef SUPPORT_TAGS
|
||||
if(this_opt) {
|
||||
opt = simple_strtol( this_opt, NULL, 0 );
|
||||
if (opt >= 0)
|
||||
setup_use_tagged_queuing = !!opt;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("mac53c9x=", mac_esp_setup);
|
||||
|
||||
|
||||
/*
|
||||
* ESP address 'detection'
|
||||
*/
|
||||
|
||||
unsigned long get_base(int chip_num)
|
||||
{
|
||||
/*
|
||||
* using the chip_num and mac model, figure out where the
|
||||
* chips are mapped
|
||||
*/
|
||||
|
||||
unsigned long io_base = 0x50f00000;
|
||||
unsigned int second_offset = 0x402;
|
||||
unsigned long scsi_loc = 0;
|
||||
|
||||
switch (macintosh_config->scsi_type) {
|
||||
|
||||
/* 950, 900, 700 */
|
||||
case MAC_SCSI_QUADRA2:
|
||||
scsi_loc = io_base + 0xf000 + ((chip_num == 0) ? 0 : second_offset);
|
||||
break;
|
||||
|
||||
/* av's */
|
||||
case MAC_SCSI_QUADRA3:
|
||||
scsi_loc = io_base + 0x18000 + ((chip_num == 0) ? 0 : second_offset);
|
||||
break;
|
||||
|
||||
/* most quadra/centris models are like this */
|
||||
case MAC_SCSI_QUADRA:
|
||||
scsi_loc = io_base + 0x10000;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("mac_esp: get_base: hit default!\n");
|
||||
scsi_loc = io_base + 0x10000;
|
||||
break;
|
||||
|
||||
} /* switch */
|
||||
|
||||
printk("mac_esp: io base at 0x%lx\n", scsi_loc);
|
||||
|
||||
return scsi_loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Model dependent ESP setup
|
||||
*/
|
||||
|
||||
int mac_esp_detect(struct scsi_host_template * tpnt)
|
||||
{
|
||||
int quick = 0;
|
||||
int chipnum, chipspresent = 0;
|
||||
#if 0
|
||||
unsigned long timeout;
|
||||
#endif
|
||||
|
||||
if (esp_initialized > 0)
|
||||
return -ENODEV;
|
||||
|
||||
/* what do we have in this machine... */
|
||||
if (MACHW_PRESENT(MAC_SCSI_96)) {
|
||||
chipspresent ++;
|
||||
}
|
||||
|
||||
if (MACHW_PRESENT(MAC_SCSI_96_2)) {
|
||||
chipspresent ++;
|
||||
}
|
||||
|
||||
/* number of ESPs present ? */
|
||||
if (setup_num_esps >= 0) {
|
||||
if (chipspresent >= setup_num_esps)
|
||||
chipspresent = setup_num_esps;
|
||||
else
|
||||
printk("mac_esp_detect: num_hosts detected %d setup %d \n",
|
||||
chipspresent, setup_num_esps);
|
||||
}
|
||||
|
||||
/* TODO: add disconnect / nosync flags */
|
||||
|
||||
/* setup variables */
|
||||
tpnt->can_queue =
|
||||
(setup_can_queue > 0) ? setup_can_queue : 7;
|
||||
tpnt->cmd_per_lun =
|
||||
(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : 1;
|
||||
tpnt->sg_tablesize =
|
||||
(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_ALL;
|
||||
|
||||
if (setup_hostid >= 0)
|
||||
tpnt->this_id = setup_hostid;
|
||||
else {
|
||||
/* use 7 as default */
|
||||
tpnt->this_id = 7;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TAGS
|
||||
if (setup_use_tagged_queuing < 0)
|
||||
setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
|
||||
#endif
|
||||
|
||||
for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
|
||||
struct NCR_ESP * esp;
|
||||
|
||||
esp = esp_allocate(tpnt, NULL, 0);
|
||||
esp->eregs = (struct ESP_regs *) get_base(chipnum);
|
||||
|
||||
esp->dma_irq_p = &esp_dafb_dma_irq_p;
|
||||
if (chipnum == 0) {
|
||||
|
||||
if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
|
||||
/* most machines except those below :-) */
|
||||
quick = 1;
|
||||
esp->dma_irq_p = &esp_iosb_dma_irq_p;
|
||||
} else if (macintosh_config->scsi_type == MAC_SCSI_QUADRA3) {
|
||||
/* mostly av's */
|
||||
quick = 0;
|
||||
} else {
|
||||
/* q950, 900, 700 */
|
||||
quick = 1;
|
||||
out_be32(0xf9800024, 0x1d1);
|
||||
esp->dregs = (void *) 0xf9800024;
|
||||
}
|
||||
|
||||
} else { /* chipnum */
|
||||
|
||||
quick = 1;
|
||||
out_be32(0xf9800028, 0x1d1);
|
||||
esp->dregs = (void *) 0xf9800028;
|
||||
|
||||
} /* chipnum == 0 */
|
||||
|
||||
/* use pio for command bytes; pio for message/data: TBI */
|
||||
esp->do_pio_cmds = 1;
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = (volatile unsigned char*) cmd_buffer;
|
||||
esp->esp_command_dvma = (__u32) cmd_buffer;
|
||||
|
||||
/* various 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 = NULL;
|
||||
esp->dma_init_write = NULL;
|
||||
esp->dma_ints_off = &dma_ints_off;
|
||||
esp->dma_ints_on = &dma_ints_on;
|
||||
|
||||
esp->dma_ports_p = &dma_ports_p;
|
||||
|
||||
|
||||
/* Optional functions */
|
||||
esp->dma_barrier = NULL;
|
||||
esp->dma_drain = NULL;
|
||||
esp->dma_invalidate = NULL;
|
||||
esp->dma_irq_entry = NULL;
|
||||
esp->dma_irq_exit = NULL;
|
||||
esp->dma_led_on = NULL;
|
||||
esp->dma_led_off = NULL;
|
||||
esp->dma_poll = NULL;
|
||||
esp->dma_reset = NULL;
|
||||
|
||||
/* SCSI chip speed */
|
||||
/* below esp->cfreq = 40000000; */
|
||||
|
||||
|
||||
if (quick) {
|
||||
/* 'quick' means there's handshake glue logic like in the 5380 case */
|
||||
esp->dma_setup = &dma_setup_quick;
|
||||
} else {
|
||||
esp->dma_setup = &dma_setup;
|
||||
}
|
||||
|
||||
if (chipnum == 0) {
|
||||
|
||||
esp->irq = IRQ_MAC_SCSI;
|
||||
|
||||
request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp->ehost);
|
||||
#if 0 /* conflicts with IOP ADB */
|
||||
request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp->ehost);
|
||||
#endif
|
||||
|
||||
if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
|
||||
esp->cfreq = 16500000;
|
||||
} else {
|
||||
esp->cfreq = 25000000;
|
||||
}
|
||||
|
||||
|
||||
} else { /* chipnum == 1 */
|
||||
|
||||
esp->irq = IRQ_MAC_SCSIDRQ;
|
||||
#if 0 /* conflicts with IOP ADB */
|
||||
request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp->ehost);
|
||||
#endif
|
||||
|
||||
esp->cfreq = 25000000;
|
||||
|
||||
}
|
||||
|
||||
if (quick) {
|
||||
printk("esp: using quick version\n");
|
||||
}
|
||||
|
||||
printk("esp: addr at 0x%p\n", esp->eregs);
|
||||
|
||||
esp->scsi_id = 7;
|
||||
esp->diff = 0;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
} /* for chipnum */
|
||||
|
||||
if (chipspresent)
|
||||
printk("\nmac_esp: %d esp controllers found\n", chipspresent);
|
||||
|
||||
esp_initialized = chipspresent;
|
||||
|
||||
return chipspresent;
|
||||
}
|
||||
|
||||
static int mac_esp_release(struct Scsi_Host *shost)
|
||||
{
|
||||
if (shost->irq)
|
||||
free_irq(shost->irq, NULL);
|
||||
if (shost->io_port && shost->n_io_port)
|
||||
release_region(shost->io_port, shost->n_io_port);
|
||||
scsi_unregister(shost);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* I've been wondering what this is supposed to do, for some time. Talking
|
||||
* to Allen Briggs: These machines have an extra register someplace where the
|
||||
* DRQ pin of the ESP can be monitored. That isn't useful for determining
|
||||
* anything else (such as reselect interrupt or other magic) though.
|
||||
* Maybe make the semantics should be changed like
|
||||
* if (esp->current_SC)
|
||||
* ... check DRQ flag ...
|
||||
* else
|
||||
* ... disconnected, check pending VIA interrupt ...
|
||||
*
|
||||
* There's a problem with using the dabf flag or mac_irq_pending() here: both
|
||||
* seem to return 1 even though no interrupt is currently pending, resulting
|
||||
* in esp_exec_cmd() holding off the next command, and possibly infinite loops
|
||||
* in esp_intr().
|
||||
* Short term fix: just use esp_status & ESP_STAT_INTR here, as long as we
|
||||
* use simple PIO. The DRQ status will be important when implementing pseudo
|
||||
* DMA mode (set up ESP transfer count, return, do a batch of bytes in PIO or
|
||||
* 'hardware handshake' mode upon DRQ).
|
||||
* If you plan on changing this (i.e. to save the esp_status register access in
|
||||
* favor of a VIA register access or a shadow register for the IFR), make sure
|
||||
* to try a debug version of this first to monitor what registers would be a good
|
||||
* indicator of the ESP interrupt.
|
||||
*/
|
||||
|
||||
static int esp_dafb_dma_irq_p(struct NCR_ESP * esp)
|
||||
{
|
||||
unsigned int ret;
|
||||
int sreg = esp_read(esp->eregs->esp_status);
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: esp_dafb_dma_irq_p dafb %d irq %d\n",
|
||||
readl(esp->dregs), mac_irq_pending(IRQ_MAC_SCSI));
|
||||
#endif
|
||||
|
||||
sreg &= ESP_STAT_INTR;
|
||||
|
||||
/*
|
||||
* maybe working; this is essentially what's used for iosb_dma_irq_p
|
||||
*/
|
||||
if (sreg)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* didn't work ...
|
||||
*/
|
||||
#if 0
|
||||
if (esp->current_SC)
|
||||
ret = readl(esp->dregs) & 0x200;
|
||||
else if (esp->disconnected_SC)
|
||||
ret = 1; /* sreg ?? */
|
||||
else
|
||||
ret = mac_irq_pending(IRQ_MAC_SCSI);
|
||||
|
||||
return(ret);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* See above: testing mac_irq_pending always returned 8 (SCSI IRQ) regardless
|
||||
* of the actual ESP status.
|
||||
*/
|
||||
|
||||
static int esp_iosb_dma_irq_p(struct NCR_ESP * esp)
|
||||
{
|
||||
int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ);
|
||||
int sreg = esp_read(esp->eregs->esp_status);
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n",
|
||||
mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI),
|
||||
sreg, esp->current_SC, esp->disconnected_SC);
|
||||
#endif
|
||||
|
||||
sreg &= ESP_STAT_INTR;
|
||||
|
||||
if (sreg)
|
||||
return (sreg);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This seems to be OK for PIO at least ... usually 0 after PIO.
|
||||
*/
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count)
|
||||
{
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma bytes sent = %x\n", fifo_count);
|
||||
#endif
|
||||
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* dma_can_transfer is used to switch between DMA and PIO, if DMA (pseudo)
|
||||
* is ever implemented. Returning 0 here will use PIO.
|
||||
*/
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd * sp)
|
||||
{
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
#if 0 /* no DMA yet; make conditional */
|
||||
if (sz > 0x10000000) {
|
||||
sz = 0x10000000;
|
||||
}
|
||||
printk("mac_esp: dma can transfer = 0lx%x\n", sz);
|
||||
#else
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: pio to transfer = %ld\n", sz);
|
||||
#endif
|
||||
|
||||
sz = 0;
|
||||
#endif
|
||||
return sz;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not yet ...
|
||||
*/
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP * esp)
|
||||
{
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_dump_state: called\n");
|
||||
#endif
|
||||
#if 0
|
||||
ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
|
||||
esp->esp_id, ((struct mac_dma_registers *)
|
||||
(esp->dregs))->cond_reg));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* DMA setup: should be used to set up the ESP transfer count for pseudo
|
||||
* DMA transfers; need a DRQ transfer function to do the actual transfer
|
||||
*/
|
||||
|
||||
static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length)
|
||||
{
|
||||
printk("mac_esp: dma_init_read\n");
|
||||
}
|
||||
|
||||
|
||||
static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
|
||||
{
|
||||
printk("mac_esp: dma_init_write\n");
|
||||
}
|
||||
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP * esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP * esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* generic dma_irq_p(), unused
|
||||
*/
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP * esp)
|
||||
{
|
||||
int i = esp_read(esp->eregs->esp_status);
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_irq_p status %d\n", i);
|
||||
#endif
|
||||
|
||||
return (i & ESP_STAT_INTR);
|
||||
}
|
||||
|
||||
static int dma_irq_p_quick(struct NCR_ESP * esp)
|
||||
{
|
||||
/*
|
||||
* Copied from iosb_dma_irq_p()
|
||||
*/
|
||||
int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ);
|
||||
int sreg = esp_read(esp->eregs->esp_status);
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n",
|
||||
mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI),
|
||||
sreg, esp->current_SC, esp->disconnected_SC);
|
||||
#endif
|
||||
|
||||
sreg &= ESP_STAT_INTR;
|
||||
|
||||
if (sreg)
|
||||
return (sreg);
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void dma_led_off(struct NCR_ESP * esp)
|
||||
{
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_led_off: called\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void dma_led_on(struct NCR_ESP * esp)
|
||||
{
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_led_on: called\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP * esp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write)
|
||||
{
|
||||
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_setup\n");
|
||||
#endif
|
||||
|
||||
if (write) {
|
||||
dma_init_read(esp, (char *) addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, (char *) addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write)
|
||||
{
|
||||
#ifdef DEBUG_MAC_ESP
|
||||
printk("mac_esp: dma_setup_quick\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "mac_esp",
|
||||
.name = "Mac 53C9x SCSI",
|
||||
.detect = mac_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = mac_esp_release,
|
||||
.info = esp_info,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = DISABLE_CLUSTERING
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,606 +0,0 @@
|
||||
/*
|
||||
* Oktagon_esp.c -- Driver for bsc Oktagon
|
||||
*
|
||||
* Written by Carsten Pluntke 1998
|
||||
*
|
||||
* Based on cyber_esp.c
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS)
|
||||
#define USE_BOTTOM_HALF
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "NCR53C9x.h"
|
||||
|
||||
#include <linux/zorro.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
|
||||
#ifdef USE_BOTTOM_HALF
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#endif
|
||||
|
||||
/* The controller registers can be found in the Z2 config area at these
|
||||
* offsets:
|
||||
*/
|
||||
#define OKTAGON_ESP_ADDR 0x03000
|
||||
#define OKTAGON_DMA_ADDR 0x01000
|
||||
|
||||
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
|
||||
static void dma_dump_state(struct NCR_ESP *esp);
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
|
||||
static void dma_ints_off(struct NCR_ESP *esp);
|
||||
static void dma_ints_on(struct NCR_ESP *esp);
|
||||
static int dma_irq_p(struct NCR_ESP *esp);
|
||||
static void dma_led_off(struct NCR_ESP *esp);
|
||||
static void dma_led_on(struct NCR_ESP *esp);
|
||||
static int dma_ports_p(struct NCR_ESP *esp);
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
|
||||
|
||||
static void dma_irq_exit(struct NCR_ESP *esp);
|
||||
static void dma_invalidate(struct NCR_ESP *esp);
|
||||
|
||||
static void dma_mmu_get_scsi_one(struct NCR_ESP *,Scsi_Cmnd *);
|
||||
static void dma_mmu_get_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *);
|
||||
static void dma_mmu_release_scsi_one(struct NCR_ESP *,Scsi_Cmnd *);
|
||||
static void dma_mmu_release_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *);
|
||||
static void dma_advance_sg(Scsi_Cmnd *);
|
||||
static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x);
|
||||
|
||||
#ifdef USE_BOTTOM_HALF
|
||||
static void dma_commit(struct work_struct *unused);
|
||||
|
||||
long oktag_to_io(long *paddr, long *addr, long len);
|
||||
long oktag_from_io(long *addr, long *paddr, long len);
|
||||
|
||||
static DECLARE_WORK(tq_fake_dma, dma_commit);
|
||||
|
||||
#define DMA_MAXTRANSFER 0x8000
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* No bottom half. Use transfer directly from IRQ. Find a narrow path
|
||||
* between too much IRQ overhead and clogging the IRQ for too long.
|
||||
*/
|
||||
|
||||
#define DMA_MAXTRANSFER 0x1000
|
||||
|
||||
#endif
|
||||
|
||||
static struct notifier_block oktagon_notifier = {
|
||||
oktagon_notify_reboot,
|
||||
NULL,
|
||||
0
|
||||
};
|
||||
|
||||
static long *paddress;
|
||||
static long *address;
|
||||
static long len;
|
||||
static long dma_on;
|
||||
static int direction;
|
||||
static struct NCR_ESP *current_esp;
|
||||
|
||||
|
||||
static volatile unsigned char cmd_buffer[16];
|
||||
/* This is where all commands are put
|
||||
* before they are trasfered to the ESP chip
|
||||
* via PIO.
|
||||
*/
|
||||
|
||||
/***************************************************************** Detection */
|
||||
int oktagon_esp_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned long address;
|
||||
struct ESP_regs *eregs;
|
||||
|
||||
while ((z = zorro_find_device(ZORRO_PROD_BSC_OKTAGON_2008, z))) {
|
||||
unsigned long board = z->resource.start;
|
||||
if (request_mem_region(board+OKTAGON_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
/*
|
||||
* It is a SCSI controller.
|
||||
* Hardwire Host adapter to SCSI ID 7
|
||||
*/
|
||||
|
||||
address = (unsigned long)ZTWO_VADDR(board);
|
||||
eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
|
||||
|
||||
/* This line was 5 lines lower */
|
||||
esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0);
|
||||
|
||||
/* we have to shift the registers only one bit for oktagon */
|
||||
esp->shift = 1;
|
||||
|
||||
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
|
||||
udelay(5);
|
||||
if (esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
|
||||
return 0; /* Bail out if address did not hold data */
|
||||
|
||||
/* 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 = &dma_invalidate;
|
||||
esp->dma_irq_entry = 0;
|
||||
esp->dma_irq_exit = &dma_irq_exit;
|
||||
esp->dma_led_on = &dma_led_on;
|
||||
esp->dma_led_off = &dma_led_off;
|
||||
esp->dma_poll = 0;
|
||||
esp->dma_reset = 0;
|
||||
|
||||
esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
|
||||
esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
|
||||
esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one;
|
||||
esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl;
|
||||
esp->dma_advance_sg = &dma_advance_sg;
|
||||
|
||||
/* SCSI chip speed */
|
||||
/* Looking at the quartz of the SCSI board... */
|
||||
esp->cfreq = 25000000;
|
||||
|
||||
/* The DMA registers on the CyberStorm are mapped
|
||||
* relative to the device (i.e. in the same Zorro
|
||||
* I/O block).
|
||||
*/
|
||||
esp->dregs = (void *)(address + OKTAGON_DMA_ADDR);
|
||||
|
||||
paddress = (long *) esp->dregs;
|
||||
|
||||
/* ESP register base */
|
||||
esp->eregs = eregs;
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = (volatile unsigned char*) cmd_buffer;
|
||||
|
||||
/* Yes, the virtual address. See below. */
|
||||
esp->esp_command_dvma = (__u32) cmd_buffer;
|
||||
|
||||
esp->irq = IRQ_AMIGA_PORTS;
|
||||
request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
|
||||
"BSC Oktagon SCSI", esp->ehost);
|
||||
|
||||
/* Figure out our scsi ID on the bus */
|
||||
esp->scsi_id = 7;
|
||||
|
||||
/* We don't have a differential SCSI-bus. */
|
||||
esp->diff = 0;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
printk("ESP_Oktagon Driver 1.1"
|
||||
#ifdef USE_BOTTOM_HALF
|
||||
" [BOTTOM_HALF]"
|
||||
#else
|
||||
" [IRQ]"
|
||||
#endif
|
||||
" registered.\n");
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
current_esp = esp;
|
||||
register_reboot_notifier(&oktagon_notifier);
|
||||
return esps_in_use;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* On certain configurations the SCSI equipment gets confused on reboot,
|
||||
* so we have to reset it then.
|
||||
*/
|
||||
|
||||
static int
|
||||
oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
|
||||
if((code == SYS_DOWN || code == SYS_HALT) && (esp = current_esp))
|
||||
{
|
||||
esp_bootup_reset(esp,esp->eregs);
|
||||
udelay(500); /* Settle time. Maybe unnecessary. */
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef USE_BOTTOM_HALF
|
||||
|
||||
|
||||
/*
|
||||
* The bsc Oktagon controller has no real DMA, so we have to do the 'DMA
|
||||
* transfer' in the interrupt (Yikes!) or use a bottom half to not to clutter
|
||||
* IRQ's for longer-than-good.
|
||||
*
|
||||
* FIXME
|
||||
* BIG PROBLEM: 'len' is usually the buffer length, not the expected length
|
||||
* of the data. So DMA may finish prematurely, further reads lead to
|
||||
* 'machine check' on APUS systems (don't know about m68k systems, AmigaOS
|
||||
* deliberately ignores the bus faults) and a normal copy-loop can't
|
||||
* be exited prematurely just at the right moment by the dma_invalidate IRQ.
|
||||
* So do it the hard way, write an own copier in assembler and
|
||||
* catch the exception.
|
||||
* -- Carsten
|
||||
*/
|
||||
|
||||
|
||||
static void dma_commit(struct work_struct *unused)
|
||||
{
|
||||
long wait,len2,pos;
|
||||
struct NCR_ESP *esp;
|
||||
|
||||
ESPDATA(("Transfer: %ld bytes, Address 0x%08lX, Direction: %d\n",
|
||||
len,(long) address,direction));
|
||||
dma_ints_off(current_esp);
|
||||
|
||||
pos = 0;
|
||||
wait = 1;
|
||||
if(direction) /* write? (memory to device) */
|
||||
{
|
||||
while(len > 0)
|
||||
{
|
||||
len2 = oktag_to_io(paddress, address+pos, len);
|
||||
if(!len2)
|
||||
{
|
||||
if(wait > 1000)
|
||||
{
|
||||
printk("Expedited DMA exit (writing) %ld\n",len);
|
||||
break;
|
||||
}
|
||||
mdelay(wait);
|
||||
wait *= 2;
|
||||
}
|
||||
pos += len2;
|
||||
len -= len2*sizeof(long);
|
||||
}
|
||||
} else {
|
||||
while(len > 0)
|
||||
{
|
||||
len2 = oktag_from_io(address+pos, paddress, len);
|
||||
if(!len2)
|
||||
{
|
||||
if(wait > 1000)
|
||||
{
|
||||
printk("Expedited DMA exit (reading) %ld\n",len);
|
||||
break;
|
||||
}
|
||||
mdelay(wait);
|
||||
wait *= 2;
|
||||
}
|
||||
pos += len2;
|
||||
len -= len2*sizeof(long);
|
||||
}
|
||||
}
|
||||
|
||||
/* to make esp->shift work */
|
||||
esp=current_esp;
|
||||
|
||||
#if 0
|
||||
len2 = (esp_read(current_esp->eregs->esp_tclow) & 0xff) |
|
||||
((esp_read(current_esp->eregs->esp_tcmed) & 0xff) << 8);
|
||||
|
||||
/*
|
||||
* Uh uh. If you see this, len and transfer count registers were out of
|
||||
* sync. That means really serious trouble.
|
||||
*/
|
||||
|
||||
if(len2)
|
||||
printk("Eeeek!! Transfer count still %ld!\n",len2);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Normally we just need to exit and wait for the interrupt to come.
|
||||
* But at least one device (my Microtek ScanMaker 630) regularly mis-
|
||||
* calculates the bytes it should send which is really ugly because
|
||||
* it locks up the SCSI bus if not accounted for.
|
||||
*/
|
||||
|
||||
if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))
|
||||
{
|
||||
long len = 100;
|
||||
long trash[10];
|
||||
|
||||
/*
|
||||
* Interrupt bit was not set. Either the device is just plain lazy
|
||||
* so we give it a 10 ms chance or...
|
||||
*/
|
||||
while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)))
|
||||
udelay(100);
|
||||
|
||||
|
||||
if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))
|
||||
{
|
||||
/*
|
||||
* So we think that the transfer count is out of sync. Since we
|
||||
* have all we want we are happy and can ditch the trash.
|
||||
*/
|
||||
|
||||
len = DMA_MAXTRANSFER;
|
||||
|
||||
while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)))
|
||||
oktag_from_io(trash,paddress,2);
|
||||
|
||||
if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))
|
||||
{
|
||||
/*
|
||||
* Things really have gone wrong. If we leave the system in that
|
||||
* state, the SCSI bus is locked forever. I hope that this will
|
||||
* turn the system in a more or less running state.
|
||||
*/
|
||||
printk("Device is bolixed, trying bus reset...\n");
|
||||
esp_bootup_reset(current_esp,current_esp->eregs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESPDATA(("Transfer_finale: do_data_finale should come\n"));
|
||||
|
||||
len = 0;
|
||||
dma_on = 0;
|
||||
dma_ints_on(current_esp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
|
||||
{
|
||||
/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
|
||||
* the number of bytes sent (to the ESP chip) equals the number
|
||||
* of bytes in the FIFO - there is no buffering in the DMA controller.
|
||||
* XXXX Do I read this right? It is from host to ESP, right?
|
||||
*/
|
||||
return fifo_count;
|
||||
}
|
||||
|
||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
unsigned long sz = sp->SCp.this_residual;
|
||||
if(sz > DMA_MAXTRANSFER)
|
||||
sz = DMA_MAXTRANSFER;
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void dma_dump_state(struct NCR_ESP *esp)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* What the f$@& is this?
|
||||
*
|
||||
* Some SCSI devices (like my Microtek ScanMaker 630 scanner) want to transfer
|
||||
* more data than requested. How much? Dunno. So ditch the bogus data into
|
||||
* the sink, hoping the device will advance to the next phase sooner or later.
|
||||
*
|
||||
* -- Carsten
|
||||
*/
|
||||
|
||||
static long oktag_eva_buffer[16]; /* The data sink */
|
||||
|
||||
static void oktag_check_dma(void)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
|
||||
esp=current_esp;
|
||||
if(!len)
|
||||
{
|
||||
address = oktag_eva_buffer;
|
||||
len = 2;
|
||||
/* esp_do_data sets them to zero like len */
|
||||
esp_write(current_esp->eregs->esp_tclow,2);
|
||||
esp_write(current_esp->eregs->esp_tcmed,0);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
|
||||
{
|
||||
/* Zorro is noncached, everything else done using processor. */
|
||||
/* cache_clear(addr, length); */
|
||||
|
||||
if(dma_on)
|
||||
panic("dma_init_read while dma process is initialized/running!\n");
|
||||
direction = 0;
|
||||
address = (long *) vaddress;
|
||||
current_esp = esp;
|
||||
len = length;
|
||||
oktag_check_dma();
|
||||
dma_on = 1;
|
||||
}
|
||||
|
||||
static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
|
||||
{
|
||||
/* cache_push(addr, length); */
|
||||
|
||||
if(dma_on)
|
||||
panic("dma_init_write while dma process is initialized/running!\n");
|
||||
direction = 1;
|
||||
address = (long *) vaddress;
|
||||
current_esp = esp;
|
||||
len = length;
|
||||
oktag_check_dma();
|
||||
dma_on = 1;
|
||||
}
|
||||
|
||||
static void dma_ints_off(struct NCR_ESP *esp)
|
||||
{
|
||||
disable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static void dma_ints_on(struct NCR_ESP *esp)
|
||||
{
|
||||
enable_irq(esp->irq);
|
||||
}
|
||||
|
||||
static int dma_irq_p(struct NCR_ESP *esp)
|
||||
{
|
||||
/* It's important to check the DMA IRQ bit in the correct way! */
|
||||
return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
|
||||
}
|
||||
|
||||
static void dma_led_off(struct NCR_ESP *esp)
|
||||
{
|
||||
}
|
||||
|
||||
static void dma_led_on(struct NCR_ESP *esp)
|
||||
{
|
||||
}
|
||||
|
||||
static int dma_ports_p(struct NCR_ESP *esp)
|
||||
{
|
||||
return ((amiga_custom.intenar) & IF_PORTS);
|
||||
}
|
||||
|
||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
|
||||
{
|
||||
/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
|
||||
* so when (write) is true, it actually means READ!
|
||||
*/
|
||||
if(write){
|
||||
dma_init_read(esp, addr, count);
|
||||
} else {
|
||||
dma_init_write(esp, addr, count);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ entry when DMA transfer is ready to be started
|
||||
*/
|
||||
|
||||
static void dma_irq_exit(struct NCR_ESP *esp)
|
||||
{
|
||||
#ifdef USE_BOTTOM_HALF
|
||||
if(dma_on)
|
||||
{
|
||||
schedule_work(&tq_fake_dma);
|
||||
}
|
||||
#else
|
||||
while(len && !dma_irq_p(esp))
|
||||
{
|
||||
if(direction)
|
||||
*paddress = *address++;
|
||||
else
|
||||
*address++ = *paddress;
|
||||
len -= (sizeof(long));
|
||||
}
|
||||
len = 0;
|
||||
dma_on = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ entry when DMA has just finished
|
||||
*/
|
||||
|
||||
static void dma_invalidate(struct NCR_ESP *esp)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the processor does the data transfer we have to use the custom
|
||||
* mmu interface to pass the virtual address, not the physical.
|
||||
*/
|
||||
|
||||
void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
sp->SCp.ptr =
|
||||
sp->request_buffer;
|
||||
}
|
||||
|
||||
void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
sp->SCp.ptr = sg_virt(sp->SCp.buffer);
|
||||
}
|
||||
|
||||
void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
}
|
||||
|
||||
void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
|
||||
{
|
||||
}
|
||||
|
||||
void dma_advance_sg(Scsi_Cmnd *sp)
|
||||
{
|
||||
sp->SCp.ptr = sg_virt(sp->SCp.buffer);
|
||||
}
|
||||
|
||||
|
||||
#define HOSTS_C
|
||||
|
||||
int oktagon_esp_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
|
||||
esp_release();
|
||||
release_mem_region(address, sizeof(struct ESP_regs));
|
||||
free_irq(IRQ_AMIGA_PORTS, esp_intr);
|
||||
unregister_reboot_notifier(&oktagon_notifier);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "esp-oktagon",
|
||||
.proc_info = &esp_proc_info,
|
||||
.name = "BSC Oktagon SCSI",
|
||||
.detect = oktagon_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = oktagon_esp_release,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = ENABLE_CLUSTERING
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -1,194 +0,0 @@
|
||||
/* -*- mode: asm -*-
|
||||
* Due to problems while transferring data I've put these routines as assembly
|
||||
* code.
|
||||
* Since I'm no PPC assembler guru, the code is just the assembler version of
|
||||
|
||||
int oktag_to_io(long *paddr,long *addr,long len)
|
||||
{
|
||||
long *addr2 = addr;
|
||||
for(len=(len+sizeof(long)-1)/sizeof(long);len--;)
|
||||
*paddr = *addr2++;
|
||||
return addr2 - addr;
|
||||
}
|
||||
|
||||
int oktag_from_io(long *addr,long *paddr,long len)
|
||||
{
|
||||
long *addr2 = addr;
|
||||
for(len=(len+sizeof(long)-1)/sizeof(long);len--;)
|
||||
*addr2++ = *paddr;
|
||||
return addr2 - addr;
|
||||
}
|
||||
|
||||
* assembled using gcc -O2 -S, with two exception catch points where data
|
||||
* is moved to/from the IO register.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef CONFIG_APUS
|
||||
|
||||
.file "oktagon_io.c"
|
||||
|
||||
gcc2_compiled.:
|
||||
/*
|
||||
.section ".text"
|
||||
*/
|
||||
.align 2
|
||||
.globl oktag_to_io
|
||||
.type oktag_to_io,@function
|
||||
oktag_to_io:
|
||||
addi 5,5,3
|
||||
srwi 5,5,2
|
||||
cmpwi 1,5,0
|
||||
mr 9,3
|
||||
mr 3,4
|
||||
addi 5,5,-1
|
||||
bc 12,6,.L3
|
||||
.L5:
|
||||
cmpwi 1,5,0
|
||||
lwz 0,0(3)
|
||||
addi 3,3,4
|
||||
addi 5,5,-1
|
||||
exp1: stw 0,0(9)
|
||||
bc 4,6,.L5
|
||||
.L3:
|
||||
ret1: subf 3,4,3
|
||||
srawi 3,3,2
|
||||
blr
|
||||
.Lfe1:
|
||||
.size oktag_to_io,.Lfe1-oktag_to_io
|
||||
.align 2
|
||||
.globl oktag_from_io
|
||||
.type oktag_from_io,@function
|
||||
oktag_from_io:
|
||||
addi 5,5,3
|
||||
srwi 5,5,2
|
||||
cmpwi 1,5,0
|
||||
mr 9,3
|
||||
addi 5,5,-1
|
||||
bc 12,6,.L9
|
||||
.L11:
|
||||
cmpwi 1,5,0
|
||||
exp2: lwz 0,0(4)
|
||||
addi 5,5,-1
|
||||
stw 0,0(3)
|
||||
addi 3,3,4
|
||||
bc 4,6,.L11
|
||||
.L9:
|
||||
ret2: subf 3,9,3
|
||||
srawi 3,3,2
|
||||
blr
|
||||
.Lfe2:
|
||||
.size oktag_from_io,.Lfe2-oktag_from_io
|
||||
.ident "GCC: (GNU) egcs-2.90.29 980515 (egcs-1.0.3 release)"
|
||||
|
||||
/*
|
||||
* Exception table.
|
||||
* Second longword shows where to jump when an exception at the addr the first
|
||||
* longword is pointing to is caught.
|
||||
*/
|
||||
|
||||
.section __ex_table,"a"
|
||||
.align 2
|
||||
oktagon_except:
|
||||
.long exp1,ret1
|
||||
.long exp2,ret2
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
The code which follows is for 680x0 based assembler and is meant for
|
||||
Linux/m68k. It was created by cross compiling the code using the
|
||||
instructions given above. I then added the four labels used in the
|
||||
exception handler table at the bottom of this file.
|
||||
- Kevin <kcozens@interlog.com>
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_AMIGA
|
||||
|
||||
.file "oktagon_io.c"
|
||||
.version "01.01"
|
||||
gcc2_compiled.:
|
||||
.text
|
||||
.align 2
|
||||
.globl oktag_to_io
|
||||
.type oktag_to_io,@function
|
||||
oktag_to_io:
|
||||
link.w %a6,#0
|
||||
move.l %d2,-(%sp)
|
||||
move.l 8(%a6),%a1
|
||||
move.l 12(%a6),%d1
|
||||
move.l %d1,%a0
|
||||
move.l 16(%a6),%d0
|
||||
addq.l #3,%d0
|
||||
lsr.l #2,%d0
|
||||
subq.l #1,%d0
|
||||
moveq.l #-1,%d2
|
||||
cmp.l %d0,%d2
|
||||
jbeq .L3
|
||||
.L5:
|
||||
exp1:
|
||||
move.l (%a0)+,(%a1)
|
||||
dbra %d0,.L5
|
||||
clr.w %d0
|
||||
subq.l #1,%d0
|
||||
jbcc .L5
|
||||
.L3:
|
||||
ret1:
|
||||
move.l %a0,%d0
|
||||
sub.l %d1,%d0
|
||||
asr.l #2,%d0
|
||||
move.l -4(%a6),%d2
|
||||
unlk %a6
|
||||
rts
|
||||
|
||||
.Lfe1:
|
||||
.size oktag_to_io,.Lfe1-oktag_to_io
|
||||
.align 2
|
||||
.globl oktag_from_io
|
||||
.type oktag_from_io,@function
|
||||
oktag_from_io:
|
||||
link.w %a6,#0
|
||||
move.l %d2,-(%sp)
|
||||
move.l 8(%a6),%d1
|
||||
move.l 12(%a6),%a1
|
||||
move.l %d1,%a0
|
||||
move.l 16(%a6),%d0
|
||||
addq.l #3,%d0
|
||||
lsr.l #2,%d0
|
||||
subq.l #1,%d0
|
||||
moveq.l #-1,%d2
|
||||
cmp.l %d0,%d2
|
||||
jbeq .L9
|
||||
.L11:
|
||||
exp2:
|
||||
move.l (%a1),(%a0)+
|
||||
dbra %d0,.L11
|
||||
clr.w %d0
|
||||
subq.l #1,%d0
|
||||
jbcc .L11
|
||||
.L9:
|
||||
ret2:
|
||||
move.l %a0,%d0
|
||||
sub.l %d1,%d0
|
||||
asr.l #2,%d0
|
||||
move.l -4(%a6),%d2
|
||||
unlk %a6
|
||||
rts
|
||||
.Lfe2:
|
||||
.size oktag_from_io,.Lfe2-oktag_from_io
|
||||
.ident "GCC: (GNU) 2.7.2.1"
|
||||
|
||||
/*
|
||||
* Exception table.
|
||||
* Second longword shows where to jump when an exception at the addr the first
|
||||
* longword is pointing to is caught.
|
||||
*/
|
||||
|
||||
.section __ex_table,"a"
|
||||
.align 2
|
||||
oktagon_except:
|
||||
.long exp1,ret1
|
||||
.long exp2,ret2
|
||||
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user