summaryrefslogtreecommitdiff
path: root/drivers/scsi/sun3_scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/sun3_scsi.c')
-rw-r--r--drivers/scsi/sun3_scsi.c831
1 files changed, 430 insertions, 401 deletions
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index e2c009b033ce..ca9cd691cc32 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -1,8 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
* Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
*
+ * VME support added by Sam Creasey
+ *
+ * TODO: modify this driver to support multiple Sun3 SCSI VME boards
+ *
* Adapted from mac_scsinew.c:
*/
/*
@@ -16,97 +21,124 @@
* Generic Generic NCR5380 driver
*
* Copyright 1995, Russell King
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
- */
-
-
-/*
- * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :)
- *
- * Options :
- *
- * PARITY - enable parity checking. Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
- *
- * USLEEP - enable support for devices that don't disconnect. Untested.
- */
-
-/*
- * $Log: sun3_NCR5380.c,v $
*/
-#define AUTOSENSE
-
#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/ctype.h>
#include <linux/delay.h>
-
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkdev.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
-
-#include <asm/sun3ints.h>
#include <asm/dvma.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-
-#define NDEBUG 0
-#define NDEBUG_ABORT 0x00100000
-#define NDEBUG_TAGS 0x00200000
-#define NDEBUG_MERGING 0x00400000
-
-/* dma on! */
-#define REAL_DMA
-
-#include "scsi.h"
-#include "initio.h"
#include <scsi/scsi_host.h>
-#include "sun3_scsi.h"
-
-static void NCR5380_print(struct Scsi_Host *instance);
-
-/* #define OLDDMA */
-#define USE_WRAPPER
-/*#define RESET_BOOT */
-#define DRIVER_SETUP
-
-/*
- * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
- */
-#ifdef BUG
-#undef RESET_BOOT
-#undef DRIVER_SETUP
-#endif
-
-/* #define SUPPORT_TAGS */
-
-#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
+/* minimum number of bytes to do dma on */
+#define DMA_MIN_SIZE 129
+
+/* Definitions for the core NCR5380 driver. */
+
+#define NCR5380_implementation_fields /* none */
+
+#define NCR5380_read(reg) in_8(hostdata->io + (reg))
+#define NCR5380_write(reg, value) out_8(hostdata->io + (reg), value)
+
+#define NCR5380_queue_command sun3scsi_queue_command
+#define NCR5380_host_reset sun3scsi_host_reset
+#define NCR5380_abort sun3scsi_abort
+#define NCR5380_info sun3scsi_info
+
+#define NCR5380_dma_xfer_len sun3scsi_dma_xfer_len
+#define NCR5380_dma_recv_setup sun3scsi_dma_count
+#define NCR5380_dma_send_setup sun3scsi_dma_count
+#define NCR5380_dma_residual sun3scsi_dma_residual
+
+#include "NCR5380.h"
+
+/* dma regs start at regbase + 8, directly after the NCR regs */
+struct sun3_dma_regs {
+ unsigned short dma_addr_hi; /* vme only */
+ unsigned short dma_addr_lo; /* vme only */
+ unsigned short dma_count_hi; /* vme only */
+ unsigned short dma_count_lo; /* vme only */
+ unsigned short udc_data; /* udc dma data reg (obio only) */
+ unsigned short udc_addr; /* uda dma addr reg (obio only) */
+ unsigned short fifo_data; /* fifo data reg,
+ * holds extra byte on odd dma reads
+ */
+ unsigned short fifo_count;
+ unsigned short csr; /* control/status reg */
+ unsigned short bpack_hi; /* vme only */
+ unsigned short bpack_lo; /* vme only */
+ unsigned short ivect; /* vme only */
+ unsigned short fifo_count_hi; /* vme only */
+};
+/* ucd chip specific regs - live in dvma space */
+struct sun3_udc_regs {
+ unsigned short rsel; /* select regs to load */
+ unsigned short addr_hi; /* high word of addr */
+ unsigned short addr_lo; /* low word */
+ unsigned short count; /* words to be xfer'd */
+ unsigned short mode_hi; /* high word of channel mode */
+ unsigned short mode_lo; /* low word of channel mode */
+};
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
-static inline unsigned char sun3scsi_read(int reg);
-static inline void sun3scsi_write(int reg, int value);
+/* addresses of the udc registers */
+#define UDC_MODE 0x38
+#define UDC_CSR 0x2e /* command/status */
+#define UDC_CHN_HI 0x26 /* chain high word */
+#define UDC_CHN_LO 0x22 /* chain lo word */
+#define UDC_CURA_HI 0x1a /* cur reg A high */
+#define UDC_CURA_LO 0x0a /* cur reg A low */
+#define UDC_CURB_HI 0x12 /* cur reg B high */
+#define UDC_CURB_LO 0x02 /* cur reg B low */
+#define UDC_MODE_HI 0x56 /* mode reg high */
+#define UDC_MODE_LO 0x52 /* mode reg low */
+#define UDC_COUNT 0x32 /* words to xfer */
+
+/* some udc commands */
+#define UDC_RESET 0
+#define UDC_CHN_START 0xa0 /* start chain */
+#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
+
+/* udc mode words */
+#define UDC_MODE_HIWORD 0x40
+#define UDC_MODE_LSEND 0xc2
+#define UDC_MODE_LRECV 0xd2
+
+/* udc reg selections */
+#define UDC_RSEL_SEND 0x282
+#define UDC_RSEL_RECV 0x182
+
+/* bits in csr reg */
+#define CSR_DMA_ACTIVE 0x8000
+#define CSR_DMA_CONFLICT 0x4000
+#define CSR_DMA_BUSERR 0x2000
+
+#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
+#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
+#define CSR_DMA_INT 0x100 /* dma interrupt pending */
+
+#define CSR_LEFT 0xc0
+#define CSR_LEFT_3 0xc0
+#define CSR_LEFT_2 0x80
+#define CSR_LEFT_1 0x40
+#define CSR_PACK_ENABLE 0x20
+
+#define CSR_DMA_ENABLE 0x10
+
+#define CSR_SEND 0x8 /* 1 = send 0 = recv */
+#define CSR_FIFO 0x2 /* reset fifo */
+#define CSR_INTR 0x4 /* interrupt enable */
+#define CSR_SCSI 0x1
+
+#define VME_DATA24 0x3d00
+
+extern int sun3_map_test(unsigned long, char *);
static int setup_can_queue = -1;
module_param(setup_can_queue, int, 0);
@@ -114,51 +146,24 @@ static int setup_cmd_per_lun = -1;
module_param(setup_cmd_per_lun, int, 0);
static int setup_sg_tablesize = -1;
module_param(setup_sg_tablesize, int, 0);
-#ifdef SUPPORT_TAGS
-static int setup_use_tagged_queuing = -1;
-module_param(setup_use_tagged_queuing, int, 0);
-#endif
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-static struct scsi_cmnd *sun3_dma_setup_done = NULL;
-
-#define AFTER_RESET_DELAY (HZ/2)
-
/* ms to wait after hitting dma regs */
#define SUN3_DMA_DELAY 10
/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
#define SUN3_DVMA_BUFSIZE 0xe000
-/* minimum number of bytes to do dma on */
-#define SUN3_DMA_MINSIZE 128
-
-static volatile unsigned char *sun3_scsi_regp;
+static struct scsi_cmnd *sun3_dma_setup_done;
static volatile struct sun3_dma_regs *dregs;
-#ifdef OLDDMA
-static unsigned char *dmabuf = NULL; /* dma memory buffer */
-#endif
-static struct sun3_udc_regs *udc_regs = NULL;
-static unsigned char *sun3_dma_orig_addr = NULL;
-static unsigned long sun3_dma_orig_count = 0;
-static int sun3_dma_active = 0;
-static unsigned long last_residual = 0;
-
-/*
- * NCR 5380 register access functions
- */
-
-static inline unsigned char sun3scsi_read(int reg)
-{
- return( sun3_scsi_regp[reg] );
-}
-
-static inline void sun3scsi_write(int reg, int value)
-{
- sun3_scsi_regp[reg] = value;
-}
+static struct sun3_udc_regs *udc_regs;
+static unsigned char *sun3_dma_orig_addr;
+static unsigned long sun3_dma_orig_count;
+static int sun3_dma_active;
+static unsigned long last_residual;
+#ifndef SUN3_SCSI_VME
/* dma controller register access functions */
static inline unsigned short sun3_udc_read(unsigned char reg)
@@ -180,273 +185,63 @@ static inline void sun3_udc_write(unsigned short val, unsigned char reg)
dregs->udc_data = val;
udelay(SUN3_DMA_DELAY);
}
-
-/*
- * XXX: status debug
- */
-static struct Scsi_Host *default_instance;
-
-/*
- * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
- *
- * Purpose : initializes mac NCR5380 driver based on the
- * command line / compile time port and irq definitions.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
- */
-
-int __init sun3scsi_detect(struct scsi_host_template * tpnt)
-{
- unsigned long ioaddr;
- static int called = 0;
- struct Scsi_Host *instance;
-
- /* check that this machine has an onboard 5380 */
- switch(idprom->id_machtype) {
- case SM_SUN3|SM_3_50:
- case SM_SUN3|SM_3_60:
- break;
-
- default:
- return 0;
- }
-
- if(called)
- return 0;
-
- tpnt->proc_name = "Sun3 5380 SCSI";
-
- /* setup variables */
- tpnt->can_queue =
- (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
- tpnt->cmd_per_lun =
- (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
- tpnt->sg_tablesize =
- (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
-
- if (setup_hostid >= 0)
- tpnt->this_id = setup_hostid;
- else {
- /* use 7 as default */
- tpnt->this_id = 7;
- }
-
- ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
- sun3_scsi_regp = (unsigned char *)ioaddr;
-
- dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
-
- if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
- == NULL) {
- printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
- return 0;
- }
-#ifdef OLDDMA
- if((dmabuf = dvma_malloc_align(SUN3_DVMA_BUFSIZE, 0x10000)) == NULL) {
- printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
- return 0;
- }
-#endif
-#ifdef SUPPORT_TAGS
- if (setup_use_tagged_queuing < 0)
- setup_use_tagged_queuing = USE_TAGGED_QUEUING;
-#endif
-
- instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
- if(instance == NULL)
- return 0;
-
- default_instance = instance;
-
- instance->io_port = (unsigned long) ioaddr;
- instance->irq = IRQ_SUN3_SCSI;
-
- NCR5380_init(instance, 0);
-
- instance->n_io_port = 32;
-
- ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
-
- if (request_irq(instance->irq, scsi_sun3_intr,
- 0, "Sun3SCSI-5380", instance)) {
-#ifndef REAL_DMA
- printk("scsi%d: IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
-#else
- printk("scsi%d: IRQ%d not free, bailing out\n",
- instance->host_no, instance->irq);
- return 0;
-#endif
- }
-
- printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
- if (instance->irq == SCSI_IRQ_NONE)
- printk ("s disabled");
- else
- printk (" %d", instance->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- instance->can_queue, instance->cmd_per_lun,
- SUN3SCSI_PUBLIC_RELEASE);
- printk("\nscsi%d:", instance->host_no);
- NCR5380_print_options(instance);
- printk("\n");
-
- dregs->csr = 0;
- udelay(SUN3_DMA_DELAY);
- dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
- udelay(SUN3_DMA_DELAY);
- dregs->fifo_count = 0;
-
- called = 1;
-
-#ifdef RESET_BOOT
- sun3_scsi_reset_boot(instance);
-#endif
-
- return 1;
-}
-
-int sun3scsi_release (struct Scsi_Host *shpnt)
-{
- if (shpnt->irq != SCSI_IRQ_NONE)
- free_irq(shpnt->irq, shpnt);
-
- iounmap((void *)sun3_scsi_regp);
-
- NCR5380_exit(shpnt);
- return 0;
-}
-
-#ifdef RESET_BOOT
-/*
- * Our 'bus reset on boot' function
- */
-
-static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
-{
- unsigned long end;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No
- * messing with the queues, interrupts, or locks necessary here.
- */
-
- printk( "Sun3 SCSI: resetting the SCSI bus..." );
-
- /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-// sun3_disable_irq( IRQ_SUN3_SCSI );
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
-
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
-
- /* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
- for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
- barrier();
-
- /* switch on SCSI IRQ again */
-// sun3_enable_irq( IRQ_SUN3_SCSI );
-
- printk( " done\n" );
-}
#endif
-const char * sun3scsi_info (struct Scsi_Host *spnt) {
- return "";
-}
-
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
+static irqreturn_t scsi_sun3_intr(int irq, void *dev)
{
+ struct Scsi_Host *instance = dev;
unsigned short csr = dregs->csr;
int handled = 0;
- if(csr & ~CSR_GOOD) {
- if(csr & CSR_DMA_BUSERR) {
- printk("scsi%d: bus error in dma\n", default_instance->host_no);
- }
+#ifdef SUN3_SCSI_VME
+ dregs->csr &= ~CSR_DMA_ENABLE;
+#endif
- if(csr & CSR_DMA_CONFLICT) {
- printk("scsi%d: dma conflict\n", default_instance->host_no);
- }
+ if(csr & ~CSR_GOOD) {
+ if (csr & CSR_DMA_BUSERR)
+ shost_printk(KERN_ERR, instance, "bus error in DMA\n");
+ if (csr & CSR_DMA_CONFLICT)
+ shost_printk(KERN_ERR, instance, "DMA conflict\n");
handled = 1;
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
handled = 1;
}
return IRQ_RETVAL(handled);
}
-/*
- * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
- * reentering NCR5380_print_status seems to have ugly side effects
- */
-
-/* this doesn't seem to get used at all -- sam */
-#if 0
-void sun3_sun3_debug (void)
-{
- unsigned long flags;
- NCR5380_local_declare();
-
- if (default_instance) {
- local_irq_save(flags);
- NCR5380_print_status(default_instance);
- local_irq_restore(flags);
- }
-}
-#endif
-
-
/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
-static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata,
+ unsigned char *data, int count, int write_flag)
{
-#ifdef OLDDMA
- if(write_flag)
- memcpy(dmabuf, data, count);
- else {
- sun3_dma_orig_addr = data;
- sun3_dma_orig_count = count;
- }
-#else
void *addr;
if(sun3_dma_orig_addr != NULL)
dvma_unmap(sun3_dma_orig_addr);
-// addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
+#ifdef SUN3_SCSI_VME
+ addr = (void *)dvma_map_vme((unsigned long) data, count);
+#else
addr = (void *)dvma_map((unsigned long) data, count);
+#endif
sun3_dma_orig_addr = addr;
sun3_dma_orig_count = count;
-#endif
+
+#ifndef SUN3_SCSI_VME
dregs->fifo_count = 0;
sun3_udc_write(UDC_RESET, UDC_CSR);
/* reset fifo */
dregs->csr &= ~CSR_FIFO;
dregs->csr |= CSR_FIFO;
+#endif
/* set direction */
if(write_flag)
@@ -454,6 +249,17 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
else
dregs->csr &= ~CSR_SEND;
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_PACK_ENABLE;
+
+ dregs->dma_addr_hi = ((unsigned long)addr >> 16);
+ dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
+
+ dregs->dma_count_hi = 0;
+ dregs->dma_count_lo = 0;
+ dregs->fifo_count_hi = 0;
+ dregs->fifo_count = 0;
+#else
/* byte count for fifo */
dregs->fifo_count = count;
@@ -464,20 +270,15 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
dregs->csr |= CSR_FIFO;
if(dregs->fifo_count != count) {
- printk("scsi%d: fifo_mismatch %04x not %04x\n",
- default_instance->host_no, dregs->fifo_count,
- (unsigned int) count);
- NCR5380_print(default_instance);
+ shost_printk(KERN_ERR, hostdata->host,
+ "FIFO mismatch %04x not %04x\n",
+ dregs->fifo_count, (unsigned int) count);
+ NCR5380_dprint(NDEBUG_DMA, hostdata->host);
}
/* setup udc */
-#ifdef OLDDMA
- udc_regs->addr_hi = ((dvma_vtob(dmabuf) & 0xff0000) >> 8);
- udc_regs->addr_lo = (dvma_vtob(dmabuf) & 0xffff);
-#else
udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
-#endif
udc_regs->count = count/2; /* count in words */
udc_regs->mode_hi = UDC_MODE_HIWORD;
if(write_flag) {
@@ -501,56 +302,115 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
/* interrupt enable */
sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
+#endif
- return count;
+ return count;
}
-static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
+static int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata,
+ unsigned char *data, int count)
{
- unsigned short resid;
+ return count;
+}
- dregs->udc_addr = 0x32;
- udelay(SUN3_DMA_DELAY);
- resid = dregs->udc_data;
- udelay(SUN3_DMA_DELAY);
- resid *= 2;
+static inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata,
+ unsigned char *data, int count)
+{
+ return sun3scsi_dma_setup(hostdata, data, count, 0);
+}
- return (unsigned long) resid;
+static inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata,
+ unsigned char *data, int count)
+{
+ return sun3scsi_dma_setup(hostdata, data, count, 1);
}
-static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata)
{
return last_residual;
}
-static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
- struct scsi_cmnd *cmd,
- int write_flag)
+static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
+ struct scsi_cmnd *cmd)
{
- if (cmd->request->cmd_type == REQ_TYPE_FS)
- return wanted;
- else
+ int wanted_len = NCR5380_to_ncmd(cmd)->this_residual;
+
+ if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(scsi_cmd_to_rq(cmd)))
return 0;
+
+ return wanted_len;
}
static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
{
+#ifdef SUN3_SCSI_VME
+ unsigned short csr;
+
+ csr = dregs->csr;
+ dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
+ dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
+
+ dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
+ dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
+
+/* if(!(csr & CSR_DMA_ENABLE))
+ * dregs->csr |= CSR_DMA_ENABLE;
+ */
+#else
sun3_udc_write(UDC_CHN_START, UDC_CSR);
+#endif
return 0;
}
/* clean up after our dma is done */
-static int sun3scsi_dma_finish(int write_flag)
+static int sun3scsi_dma_finish(enum dma_data_direction data_dir)
{
- unsigned short count;
+ const bool write_flag = data_dir == DMA_TO_DEVICE;
+ unsigned short __maybe_unused count;
unsigned short fifo;
int ret = 0;
sun3_dma_active = 0;
-#if 1
+
+#ifdef SUN3_SCSI_VME
+ dregs->csr &= ~CSR_DMA_ENABLE;
+
+ fifo = dregs->fifo_count;
+ if (write_flag) {
+ if ((fifo > 0) && (fifo < sun3_dma_orig_count))
+ fifo++;
+ }
+
+ last_residual = fifo;
+ /* empty bytes from the fifo which didn't make it */
+ if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
+ unsigned char *vaddr;
+
+ vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
+
+ vaddr += (sun3_dma_orig_count - fifo);
+ vaddr--;
+
+ switch (dregs->csr & CSR_LEFT) {
+ case CSR_LEFT_3:
+ *vaddr = (dregs->bpack_lo & 0xff00) >> 8;
+ vaddr--;
+ fallthrough;
+
+ case CSR_LEFT_2:
+ *vaddr = (dregs->bpack_hi & 0x00ff);
+ vaddr--;
+ fallthrough;
+
+ case CSR_LEFT_1:
+ *vaddr = (dregs->bpack_hi & 0xff00) >> 8;
+ break;
+ }
+ }
+#else
// check to empty the fifo on a read
if(!write_flag) {
int tmo = 20000; /* .2 sec */
@@ -566,28 +426,11 @@ static int sun3scsi_dma_finish(int write_flag)
udelay(10);
}
}
-
-#endif
-
- count = sun3scsi_dma_count(default_instance);
-#ifdef OLDDMA
-
- /* if we've finished a read, copy out the data we read */
- if(sun3_dma_orig_addr) {
- /* check for residual bytes after dma end */
- if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
- (BASR_PHASE_MATCH | BASR_ACK))) {
- printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
- printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
- ret = count;
- }
-
- /* copy in what we dma'd no matter what */
- memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
- sun3_dma_orig_addr = NULL;
- }
-#else
+ dregs->udc_addr = 0x32;
+ udelay(SUN3_DMA_DELAY);
+ count = 2 * dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
fifo = dregs->fifo_count;
last_residual = fifo;
@@ -605,10 +448,23 @@ static int sun3scsi_dma_finish(int write_flag)
vaddr[-2] = (data & 0xff00) >> 8;
vaddr[-1] = (data & 0xff);
}
+#endif
dvma_unmap(sun3_dma_orig_addr);
sun3_dma_orig_addr = NULL;
-#endif
+
+#ifdef SUN3_SCSI_VME
+ dregs->dma_addr_hi = 0;
+ dregs->dma_addr_lo = 0;
+ dregs->dma_count_hi = 0;
+ dregs->dma_count_lo = 0;
+
+ dregs->fifo_count = 0;
+ dregs->fifo_count_hi = 0;
+
+ dregs->csr &= ~CSR_SEND;
+/* dregs->csr |= CSR_DMA_ENABLE; */
+#else
sun3_udc_write(UDC_RESET, UDC_CSR);
dregs->fifo_count = 0;
dregs->csr &= ~CSR_SEND;
@@ -616,6 +472,7 @@ static int sun3scsi_dma_finish(int write_flag)
/* reset fifo */
dregs->csr &= ~CSR_FIFO;
dregs->csr |= CSR_FIFO;
+#endif
sun3_dma_setup_done = NULL;
@@ -623,25 +480,197 @@ static int sun3scsi_dma_finish(int write_flag)
}
-#include "sun3_NCR5380.c"
+#include "NCR5380.c"
+
+#ifdef SUN3_SCSI_VME
+#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI"
+#define DRV_MODULE_NAME "sun3_scsi_vme"
+#else
+#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI"
+#define DRV_MODULE_NAME "sun3_scsi"
+#endif
-static struct scsi_host_template driver_template = {
- .show_info = sun3scsi_show_info,
+#define PFX DRV_MODULE_NAME ": "
+
+static struct scsi_host_template sun3_scsi_template = {
+ .module = THIS_MODULE,
+ .proc_name = DRV_MODULE_NAME,
.name = SUN3_SCSI_NAME,
- .detect = sun3scsi_detect,
- .release = sun3scsi_release,
.info = sun3scsi_info,
.queuecommand = sun3scsi_queue_command,
- .eh_abort_handler = sun3scsi_abort,
- .eh_bus_reset_handler = sun3scsi_bus_reset,
- .can_queue = CAN_QUEUE,
+ .eh_abort_handler = sun3scsi_abort,
+ .eh_host_reset_handler = sun3scsi_host_reset,
+ .can_queue = 16,
.this_id = 7,
- .sg_tablesize = SG_TABLESIZE,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING
+ .sg_tablesize = 1,
+ .cmd_per_lun = 2,
+ .dma_boundary = PAGE_SIZE - 1,
+ .cmd_size = sizeof(struct NCR5380_cmd),
};
+static int __init sun3_scsi_probe(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance;
+ struct NCR5380_hostdata *hostdata;
+ int error;
+ struct resource *irq, *mem;
+ void __iomem *ioaddr;
+ int host_flags = 0;
+#ifdef SUN3_SCSI_VME
+ int i;
+#endif
+
+ if (setup_can_queue > 0)
+ sun3_scsi_template.can_queue = setup_can_queue;
+ if (setup_cmd_per_lun > 0)
+ sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
+ if (setup_sg_tablesize > 0)
+ sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
+ if (setup_hostid >= 0)
+ sun3_scsi_template.this_id = setup_hostid & 7;
+
+#ifdef SUN3_SCSI_VME
+ ioaddr = NULL;
+ for (i = 0; i < 2; i++) {
+ unsigned char x;
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!irq || !mem)
+ break;
+
+ ioaddr = sun3_ioremap(mem->start, resource_size(mem),
+ SUN3_PAGE_TYPE_VME16);
+ dregs = (struct sun3_dma_regs *)(ioaddr + 8);
+
+ if (sun3_map_test((unsigned long)dregs, &x)) {
+ unsigned short oldcsr;
+
+ oldcsr = dregs->csr;
+ dregs->csr = 0;
+ udelay(SUN3_DMA_DELAY);
+ if (dregs->csr == 0x1400)
+ break;
+
+ dregs->csr = oldcsr;
+ }
+
+ iounmap(ioaddr);
+ ioaddr = NULL;
+ }
+ if (!ioaddr)
+ return -ENODEV;
+#else
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!irq || !mem)
+ return -ENODEV;
+
+ ioaddr = ioremap(mem->start, resource_size(mem));
+ dregs = (struct sun3_dma_regs *)(ioaddr + 8);
+
+ udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
+ if (!udc_regs) {
+ pr_err(PFX "couldn't allocate DVMA memory!\n");
+ iounmap(ioaddr);
+ return -ENOMEM;
+ }
+#endif
+
+ instance = scsi_host_alloc(&sun3_scsi_template,
+ sizeof(struct NCR5380_hostdata));
+ if (!instance) {
+ error = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ instance->irq = irq->start;
+
+ hostdata = shost_priv(instance);
+ hostdata->base = mem->start;
+ hostdata->io = ioaddr;
+
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
+
+ error = request_irq(instance->irq, scsi_sun3_intr, 0,
+ "NCR5380", instance);
+ if (error) {
+ pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
+ instance->host_no, instance->irq);
+ goto fail_irq;
+ }
+
+ dregs->csr = 0;
+ udelay(SUN3_DMA_DELAY);
+ dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+ udelay(SUN3_DMA_DELAY);
+ dregs->fifo_count = 0;
+#ifdef SUN3_SCSI_VME
+ dregs->fifo_count_hi = 0;
+ dregs->dma_addr_hi = 0;
+ dregs->dma_addr_lo = 0;
+ dregs->dma_count_hi = 0;
+ dregs->dma_count_lo = 0;
+
+ dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
+#endif
+
+ NCR5380_maybe_reset_bus(instance);
+
+ error = scsi_add_host(instance, NULL);
+ if (error)
+ goto fail_host;
+
+ platform_set_drvdata(pdev, instance);
+
+ scsi_scan_host(instance);
+ return 0;
+
+fail_host:
+ free_irq(instance->irq, instance);
+fail_irq:
+ NCR5380_exit(instance);
+fail_init:
+ scsi_host_put(instance);
+fail_alloc:
+ if (udc_regs)
+ dvma_free(udc_regs);
+ iounmap(ioaddr);
+ return error;
+}
+
+static void __exit sun3_scsi_remove(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance = platform_get_drvdata(pdev);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ void __iomem *ioaddr = hostdata->io;
+
+ scsi_remove_host(instance);
+ free_irq(instance->irq, instance);
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+ if (udc_regs)
+ dvma_free(udc_regs);
+ iounmap(ioaddr);
+}
+
+/*
+ * sun3_scsi_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver sun3_scsi_driver __refdata = {
+ .remove = __exit_p(sun3_scsi_remove),
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ },
+};
-#include "scsi_module.c"
+module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
+MODULE_DESCRIPTION("Sun3 NCR5380 SCSI controller driver");
MODULE_LICENSE("GPL");