mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	[SCSI] sun3x_esp: convert to esp_scsi
Converted sun3x_esp driver to use esp_scsi.c Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
		
							parent
							
								
									f8d9d654fc
								
							
						
					
					
						commit
						0bb67f1818
					
				
					 3 changed files with 265 additions and 340 deletions
				
			
		| 
						 | 
				
			
			@ -1779,6 +1779,7 @@ config SUN3_SCSI
 | 
			
		|||
config SUN3X_ESP
 | 
			
		||||
	bool "Sun3x ESP SCSI"
 | 
			
		||||
	depends on SUN3X && SCSI=y
 | 
			
		||||
	select SCSI_SPI_ATTRS
 | 
			
		||||
	help
 | 
			
		||||
	  The ESP was an on-board SCSI controller used on Sun 3/80
 | 
			
		||||
	  machines.  Say Y here to compile in support for it.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ obj-$(CONFIG_SCSI_3W_9XXX)	+= 3w-9xxx.o
 | 
			
		|||
obj-$(CONFIG_SCSI_PPA)		+= ppa.o
 | 
			
		||||
obj-$(CONFIG_SCSI_IMM)		+= imm.o
 | 
			
		||||
obj-$(CONFIG_JAZZ_ESP)		+= esp_scsi.o	jazz_esp.o
 | 
			
		||||
obj-$(CONFIG_SUN3X_ESP)		+= NCR53C9x.o	sun3x_esp.o
 | 
			
		||||
obj-$(CONFIG_SUN3X_ESP)		+= esp_scsi.o	sun3x_esp.o
 | 
			
		||||
obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
 | 
			
		||||
obj-$(CONFIG_SCSI_SNI_53C710)	+= 53c700.o sni_53c710.o
 | 
			
		||||
obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,392 +1,316 @@
 | 
			
		|||
/* sun3x_esp.c:  EnhancedScsiProcessor Sun3x SCSI driver code.
 | 
			
		||||
/* sun3x_esp.c: ESP front-end for Sun3x systems.
 | 
			
		||||
 *
 | 
			
		||||
 * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
 | 
			
		||||
 *
 | 
			
		||||
 * Based on David S. Miller's esp driver
 | 
			
		||||
 * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/kernel.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/delay.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
 | 
			
		||||
#include "scsi.h"
 | 
			
		||||
#include <scsi/scsi_host.h>
 | 
			
		||||
#include "NCR53C9x.h"
 | 
			
		||||
 | 
			
		||||
#include <asm/sun3x.h>
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
#include <asm/dma.h>
 | 
			
		||||
#include <asm/dvma.h>
 | 
			
		||||
#include <asm/irq.h>
 | 
			
		||||
 | 
			
		||||
static void dma_barrier(struct NCR_ESP *esp);
 | 
			
		||||
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_drain(struct NCR_ESP *esp);
 | 
			
		||||
static void dma_invalidate(struct NCR_ESP *esp);
 | 
			
		||||
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_poll(struct NCR_ESP *esp, unsigned char *vaddr);
 | 
			
		||||
static int  dma_ports_p(struct NCR_ESP *esp);
 | 
			
		||||
static void dma_reset(struct NCR_ESP *esp);
 | 
			
		||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
 | 
			
		||||
static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp);
 | 
			
		||||
static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
 | 
			
		||||
static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp);
 | 
			
		||||
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
 | 
			
		||||
static void dma_advance_sg (Scsi_Cmnd *sp);
 | 
			
		||||
/* DMA controller reg offsets */
 | 
			
		||||
#define DMA_CSR		0x00UL	/* rw  DMA control/status register    0x00   */
 | 
			
		||||
#define DMA_ADDR        0x04UL	/* rw  DMA transfer address register  0x04   */
 | 
			
		||||
#define DMA_COUNT       0x08UL	/* rw  DMA transfer count register    0x08   */
 | 
			
		||||
#define DMA_TEST        0x0cUL	/* rw  DMA test/debug register        0x0c   */
 | 
			
		||||
 | 
			
		||||
/* Detecting ESP chips on the machine.  This is the simple and easy
 | 
			
		||||
 * version.
 | 
			
		||||
#include <scsi/scsi_host.h>
 | 
			
		||||
 | 
			
		||||
#include "esp_scsi.h"
 | 
			
		||||
 | 
			
		||||
#define DRV_MODULE_NAME		"sun3x_esp"
 | 
			
		||||
#define PFX DRV_MODULE_NAME	": "
 | 
			
		||||
#define DRV_VERSION		"1.000"
 | 
			
		||||
#define DRV_MODULE_RELDATE	"Nov 1, 2007"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * m68k always assumes readl/writel operate on little endian
 | 
			
		||||
 * mmio space; this is wrong at least for Sun3x, so we
 | 
			
		||||
 * need to workaround this until a proper way is found
 | 
			
		||||
 */
 | 
			
		||||
int sun3x_esp_detect(struct scsi_host_template *tpnt)
 | 
			
		||||
#if 0
 | 
			
		||||
#define dma_read32(REG) \
 | 
			
		||||
	readl(esp->dma_regs + (REG))
 | 
			
		||||
#define dma_write32(VAL, REG) \
 | 
			
		||||
	writel((VAL), esp->dma_regs + (REG))
 | 
			
		||||
#else
 | 
			
		||||
#define dma_read32(REG) \
 | 
			
		||||
	*(volatile u32 *)(esp->dma_regs + (REG))
 | 
			
		||||
#define dma_write32(VAL, REG) \
 | 
			
		||||
	do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg)
 | 
			
		||||
{
 | 
			
		||||
	struct NCR_ESP *esp;
 | 
			
		||||
	struct ConfigDev *esp_dev;
 | 
			
		||||
 | 
			
		||||
	esp_dev = 0;
 | 
			
		||||
	esp = esp_allocate(tpnt, esp_dev, 0);
 | 
			
		||||
 | 
			
		||||
	/* Do command transfer with DMA */
 | 
			
		||||
	esp->do_pio_cmds = 0;
 | 
			
		||||
 | 
			
		||||
	/* 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 = &dma_barrier;
 | 
			
		||||
	esp->dma_invalidate = &dma_invalidate;
 | 
			
		||||
	esp->dma_drain = &dma_drain;
 | 
			
		||||
	esp->dma_irq_entry = 0;
 | 
			
		||||
	esp->dma_irq_exit = 0;
 | 
			
		||||
	esp->dma_led_on = 0;
 | 
			
		||||
	esp->dma_led_off = 0;
 | 
			
		||||
	esp->dma_poll = &dma_poll;
 | 
			
		||||
	esp->dma_reset = &dma_reset;
 | 
			
		||||
 | 
			
		||||
        /* virtual DMA functions */
 | 
			
		||||
        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 */
 | 
			
		||||
	esp->cfreq = 20000000;
 | 
			
		||||
	esp->eregs = (struct ESP_regs *)(SUN3X_ESP_BASE);
 | 
			
		||||
	esp->dregs = (void *)SUN3X_ESP_DMA;
 | 
			
		||||
 | 
			
		||||
	esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE);
 | 
			
		||||
	esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command);
 | 
			
		||||
 | 
			
		||||
	esp->irq = 2;
 | 
			
		||||
	if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
 | 
			
		||||
			"SUN3X SCSI", esp->ehost)) {
 | 
			
		||||
		esp_deallocate(esp);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	esp->scsi_id = 7;
 | 
			
		||||
	esp->diff = 0;
 | 
			
		||||
 | 
			
		||||
	esp_initialize(esp);
 | 
			
		||||
 | 
			
		||||
 	/* for reasons beyond my knowledge (and which should likely be fixed)
 | 
			
		||||
 	   sync mode doesn't work on a 3/80 at 5mhz.  but it does at 4. */
 | 
			
		||||
 	esp->sync_defp = 0x3f;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
	writeb(val, esp->regs + (reg * 4UL));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_do_drain(struct NCR_ESP *esp)
 | 
			
		||||
static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg)
 | 
			
		||||
{
 | 
			
		||||
 	struct sparc_dma_registers *dregs =
 | 
			
		||||
 		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
 	
 | 
			
		||||
 	int count = 500000;
 | 
			
		||||
 
 | 
			
		||||
 	while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) 
 | 
			
		||||
 		udelay(1);
 | 
			
		||||
 
 | 
			
		||||
 	if(!count) {
 | 
			
		||||
 		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	dregs->cond_reg |= DMA_FIFO_STDRAIN;
 | 
			
		||||
 	
 | 
			
		||||
 	count = 500000;
 | 
			
		||||
 
 | 
			
		||||
 	while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) 
 | 
			
		||||
 		udelay(1);
 | 
			
		||||
 
 | 
			
		||||
 	if(!count) {
 | 
			
		||||
 		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
static void dma_barrier(struct NCR_ESP *esp)
 | 
			
		||||
{
 | 
			
		||||
  	struct sparc_dma_registers *dregs =
 | 
			
		||||
  		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
 	int count = 500000;
 | 
			
		||||
  
 | 
			
		||||
 	while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0))
 | 
			
		||||
  		udelay(1);
 | 
			
		||||
 
 | 
			
		||||
 	if(!count) {
 | 
			
		||||
 		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
  	dregs->cond_reg &= ~(DMA_ENABLE);
 | 
			
		||||
	return readb(esp->regs + (reg * 4UL));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This uses various DMA csr fields and the fifo flags count value to
 | 
			
		||||
 * determine how many bytes were successfully sent/received by the ESP.
 | 
			
		||||
 */
 | 
			
		||||
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
 | 
			
		||||
static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf,
 | 
			
		||||
				      size_t sz, int dir)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs = 
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
 | 
			
		||||
	int rval = dregs->st_addr - esp->esp_command_dvma;
 | 
			
		||||
 | 
			
		||||
	return rval - fifo_count;
 | 
			
		||||
	return dma_map_single(esp->dev, buf, sz, dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 | 
			
		||||
static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg,
 | 
			
		||||
				  int num_sg, int dir)
 | 
			
		||||
{
 | 
			
		||||
	return sp->SCp.this_residual;
 | 
			
		||||
	return dma_map_sg(esp->dev, sg, num_sg, dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_drain(struct NCR_ESP *esp)
 | 
			
		||||
static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr,
 | 
			
		||||
				  size_t sz, int dir)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs =
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
	int count = 500000;
 | 
			
		||||
	dma_unmap_single(esp->dev, addr, sz, dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if(dregs->cond_reg & DMA_FIFO_ISDRAIN) {
 | 
			
		||||
		dregs->cond_reg |= DMA_FIFO_STDRAIN;
 | 
			
		||||
		while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0))
 | 
			
		||||
			udelay(1);
 | 
			
		||||
		if(!count) {
 | 
			
		||||
			printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
 | 
			
		||||
static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
 | 
			
		||||
			      int num_sg, int dir)
 | 
			
		||||
{
 | 
			
		||||
	dma_unmap_sg(esp->dev, sg, num_sg, dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sun3x_esp_irq_pending(struct esp *esp)
 | 
			
		||||
{
 | 
			
		||||
	if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sun3x_esp_reset_dma(struct esp *esp)
 | 
			
		||||
{
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	val = dma_read32(DMA_CSR);
 | 
			
		||||
	dma_write32(val | DMA_RST_SCSI, DMA_CSR);
 | 
			
		||||
	dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
 | 
			
		||||
 | 
			
		||||
	/* Enable interrupts.  */
 | 
			
		||||
	val = dma_read32(DMA_CSR);
 | 
			
		||||
	dma_write32(val | DMA_INT_ENAB, DMA_CSR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sun3x_esp_dma_drain(struct esp *esp)
 | 
			
		||||
{
 | 
			
		||||
	u32 csr;
 | 
			
		||||
	int lim;
 | 
			
		||||
 | 
			
		||||
	csr = dma_read32(DMA_CSR);
 | 
			
		||||
	if (!(csr & DMA_FIFO_ISDRAIN))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
 | 
			
		||||
 | 
			
		||||
	lim = 1000;
 | 
			
		||||
	while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
 | 
			
		||||
		if (--lim == 0) {
 | 
			
		||||
			printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
 | 
			
		||||
			       esp->host->unique_id);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_invalidate(struct NCR_ESP *esp)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs =
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
 | 
			
		||||
	__u32 tmp;
 | 
			
		||||
	int count = 500000;
 | 
			
		||||
 | 
			
		||||
	while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0)) 
 | 
			
		||||
		udelay(1);
 | 
			
		||||
 | 
			
		||||
	if(!count) {
 | 
			
		||||
		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dregs->cond_reg = tmp | DMA_FIFO_INV;
 | 
			
		||||
	dregs->cond_reg &= ~DMA_FIFO_INV;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_dump_state(struct NCR_ESP *esp)
 | 
			
		||||
static void sun3x_esp_dma_invalidate(struct esp *esp)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs =
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
	u32 val;
 | 
			
		||||
	int lim;
 | 
			
		||||
 | 
			
		||||
	ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n",
 | 
			
		||||
		esp->esp_id, dregs->cond_reg, dregs->st_addr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs = 
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
 | 
			
		||||
	dregs->st_addr = vaddress;
 | 
			
		||||
	dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs = 
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
 | 
			
		||||
	/* Set up the DMA counters */
 | 
			
		||||
 | 
			
		||||
	dregs->st_addr = vaddress;
 | 
			
		||||
	dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_ints_off(struct NCR_ESP *esp)
 | 
			
		||||
{
 | 
			
		||||
	DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_ints_on(struct NCR_ESP *esp)
 | 
			
		||||
{
 | 
			
		||||
	DMA_INTSON((struct sparc_dma_registers *) esp->dregs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dma_irq_p(struct NCR_ESP *esp)
 | 
			
		||||
{
 | 
			
		||||
	return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr)
 | 
			
		||||
{
 | 
			
		||||
	int count = 50;
 | 
			
		||||
	dma_do_drain(esp);
 | 
			
		||||
 | 
			
		||||
	/* Wait till the first bits settle. */
 | 
			
		||||
	while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0))
 | 
			
		||||
	lim = 1000;
 | 
			
		||||
	while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
 | 
			
		||||
		if (--lim == 0) {
 | 
			
		||||
			printk(KERN_ALERT PFX "esp%d: DMA will not "
 | 
			
		||||
			       "invalidate!\n", esp->host->unique_id);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		udelay(1);
 | 
			
		||||
 | 
			
		||||
	if(!count) {
 | 
			
		||||
//		printk("%s:%d timeout expire (data %02x)\n", __FILE__, __LINE__,
 | 
			
		||||
//		       esp_read(esp->eregs->esp_fdata));
 | 
			
		||||
		//mach_halt();
 | 
			
		||||
		vaddr[0] = esp_read(esp->eregs->esp_fdata);
 | 
			
		||||
		vaddr[1] = esp_read(esp->eregs->esp_fdata);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}	
 | 
			
		||||
 | 
			
		||||
static int dma_ports_p(struct NCR_ESP *esp)
 | 
			
		||||
{
 | 
			
		||||
	return (((struct sparc_dma_registers *) esp->dregs)->cond_reg 
 | 
			
		||||
			& DMA_INT_ENAB);
 | 
			
		||||
	val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
 | 
			
		||||
	val |= DMA_FIFO_INV;
 | 
			
		||||
	dma_write32(val, DMA_CSR);
 | 
			
		||||
	val &= ~DMA_FIFO_INV;
 | 
			
		||||
	dma_write32(val, DMA_CSR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Resetting various pieces of the ESP scsi driver chipset/buses. */
 | 
			
		||||
static void dma_reset(struct NCR_ESP *esp)
 | 
			
		||||
static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
 | 
			
		||||
				  u32 dma_count, int write, u8 cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs =
 | 
			
		||||
		(struct sparc_dma_registers *)esp->dregs;
 | 
			
		||||
	u32 csr;
 | 
			
		||||
 | 
			
		||||
	/* Punt the DVMA into a known state. */
 | 
			
		||||
	dregs->cond_reg |= DMA_RST_SCSI;
 | 
			
		||||
	dregs->cond_reg &= ~(DMA_RST_SCSI);
 | 
			
		||||
	DMA_INTSON(dregs);
 | 
			
		||||
	BUG_ON(!(cmd & ESP_CMD_DMA));
 | 
			
		||||
 | 
			
		||||
	sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
 | 
			
		||||
	sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
 | 
			
		||||
	csr = dma_read32(DMA_CSR);
 | 
			
		||||
	csr |= DMA_ENABLE;
 | 
			
		||||
	if (write)
 | 
			
		||||
		csr |= DMA_ST_WRITE;
 | 
			
		||||
	else
 | 
			
		||||
		csr &= ~DMA_ST_WRITE;
 | 
			
		||||
	dma_write32(csr, DMA_CSR);
 | 
			
		||||
	dma_write32(addr, DMA_ADDR);
 | 
			
		||||
 | 
			
		||||
	scsi_esp_cmd(esp, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
 | 
			
		||||
static int sun3x_esp_dma_error(struct esp *esp)
 | 
			
		||||
{
 | 
			
		||||
	struct sparc_dma_registers *dregs = 
 | 
			
		||||
		(struct sparc_dma_registers *) esp->dregs;
 | 
			
		||||
	unsigned long nreg = dregs->cond_reg;
 | 
			
		||||
	u32 csr = dma_read32(DMA_CSR);
 | 
			
		||||
 | 
			
		||||
//	printk("dma_setup %c addr %08x cnt %08x\n",
 | 
			
		||||
//	       write ? 'W' : 'R', addr, count);
 | 
			
		||||
	if (csr & DMA_HNDL_ERROR)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	dma_do_drain(esp);
 | 
			
		||||
 | 
			
		||||
	if(write)
 | 
			
		||||
		nreg |= DMA_ST_WRITE;
 | 
			
		||||
	else {
 | 
			
		||||
		nreg &= ~(DMA_ST_WRITE);
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
	nreg |= DMA_ENABLE;
 | 
			
		||||
	dregs->cond_reg = nreg;
 | 
			
		||||
	dregs->st_addr = addr;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
 | 
			
		||||
{
 | 
			
		||||
    sp->SCp.have_data_in = dvma_map((unsigned long)sp->SCp.buffer,
 | 
			
		||||
				       sp->SCp.this_residual);
 | 
			
		||||
    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
 | 
			
		||||
{
 | 
			
		||||
    int sz = sp->SCp.buffers_residual;
 | 
			
		||||
    struct scatterlist *sg = sp->SCp.buffer;
 | 
			
		||||
 | 
			
		||||
    while (sz >= 0) {
 | 
			
		||||
	    sg[sz].dma_address = dvma_map((unsigned long)sg_virt(&sg[sz]),
 | 
			
		||||
					  sg[sz].length);
 | 
			
		||||
	    sz--;
 | 
			
		||||
    }
 | 
			
		||||
    sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
 | 
			
		||||
{
 | 
			
		||||
    dvma_unmap((char *)sp->SCp.have_data_in);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
 | 
			
		||||
{
 | 
			
		||||
    int sz = sp->use_sg - 1;
 | 
			
		||||
    struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
 | 
			
		||||
                        
 | 
			
		||||
    while(sz >= 0) {
 | 
			
		||||
        dvma_unmap((char *)sg[sz].dma_address);
 | 
			
		||||
        sz--;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dma_advance_sg (Scsi_Cmnd *sp)
 | 
			
		||||
{
 | 
			
		||||
    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sun3x_esp_release(struct Scsi_Host *instance)
 | 
			
		||||
{
 | 
			
		||||
	/* this code does not support being compiled as a module */	 
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct scsi_host_template driver_template = {
 | 
			
		||||
	.proc_name		= "sun3x_esp",
 | 
			
		||||
	.proc_info		= &esp_proc_info,
 | 
			
		||||
	.name			= "Sun ESP 100/100a/200",
 | 
			
		||||
	.detect			= sun3x_esp_detect,
 | 
			
		||||
	.release                = sun3x_esp_release,
 | 
			
		||||
	.slave_alloc		= esp_slave_alloc,
 | 
			
		||||
	.slave_destroy		= esp_slave_destroy,
 | 
			
		||||
	.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,
 | 
			
		||||
static const struct esp_driver_ops sun3x_esp_ops = {
 | 
			
		||||
	.esp_write8	=	sun3x_esp_write8,
 | 
			
		||||
	.esp_read8	=	sun3x_esp_read8,
 | 
			
		||||
	.map_single	=	sun3x_esp_map_single,
 | 
			
		||||
	.map_sg		=	sun3x_esp_map_sg,
 | 
			
		||||
	.unmap_single	=	sun3x_esp_unmap_single,
 | 
			
		||||
	.unmap_sg	=	sun3x_esp_unmap_sg,
 | 
			
		||||
	.irq_pending	=	sun3x_esp_irq_pending,
 | 
			
		||||
	.reset_dma	=	sun3x_esp_reset_dma,
 | 
			
		||||
	.dma_drain	=	sun3x_esp_dma_drain,
 | 
			
		||||
	.dma_invalidate	=	sun3x_esp_dma_invalidate,
 | 
			
		||||
	.send_dma_cmd	=	sun3x_esp_send_dma_cmd,
 | 
			
		||||
	.dma_error	=	sun3x_esp_dma_error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __devinit esp_sun3x_probe(struct platform_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct scsi_host_template *tpnt = &scsi_esp_template;
 | 
			
		||||
	struct Scsi_Host *host;
 | 
			
		||||
	struct esp *esp;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	int err = -ENOMEM;
 | 
			
		||||
 | 
			
		||||
#include "scsi_module.c"
 | 
			
		||||
	host = scsi_host_alloc(tpnt, sizeof(struct esp));
 | 
			
		||||
	if (!host)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	host->max_id = 8;
 | 
			
		||||
	esp = shost_priv(host);
 | 
			
		||||
 | 
			
		||||
	esp->host = host;
 | 
			
		||||
	esp->dev = dev;
 | 
			
		||||
	esp->ops = &sun3x_esp_ops;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (!res && !res->start)
 | 
			
		||||
		goto fail_unlink;
 | 
			
		||||
 | 
			
		||||
	esp->regs = ioremap_nocache(res->start, 0x20);
 | 
			
		||||
	if (!esp->regs)
 | 
			
		||||
		goto fail_unmap_regs;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(dev, IORESOURCE_MEM, 1);
 | 
			
		||||
	if (!res && !res->start)
 | 
			
		||||
		goto fail_unmap_regs;
 | 
			
		||||
 | 
			
		||||
	esp->dma_regs = ioremap_nocache(res->start, 0x10);
 | 
			
		||||
 | 
			
		||||
	esp->command_block = dma_alloc_coherent(esp->dev, 16,
 | 
			
		||||
						&esp->command_block_dma,
 | 
			
		||||
						GFP_KERNEL);
 | 
			
		||||
	if (!esp->command_block)
 | 
			
		||||
		goto fail_unmap_regs_dma;
 | 
			
		||||
 | 
			
		||||
	host->irq = platform_get_irq(dev, 0);
 | 
			
		||||
	err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
 | 
			
		||||
			  "SUN3X ESP", esp);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		goto fail_unmap_command_block;
 | 
			
		||||
 | 
			
		||||
	esp->scsi_id = 7;
 | 
			
		||||
	esp->host->this_id = esp->scsi_id;
 | 
			
		||||
	esp->scsi_id_mask = (1 << esp->scsi_id);
 | 
			
		||||
	esp->cfreq = 20000000;
 | 
			
		||||
 | 
			
		||||
	dev_set_drvdata(&dev->dev, esp);
 | 
			
		||||
 | 
			
		||||
	err = scsi_esp_register(esp, &dev->dev);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto fail_free_irq;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail_free_irq:
 | 
			
		||||
	free_irq(host->irq, esp);
 | 
			
		||||
fail_unmap_command_block:
 | 
			
		||||
	dma_free_coherent(esp->dev, 16,
 | 
			
		||||
			  esp->command_block,
 | 
			
		||||
			  esp->command_block_dma);
 | 
			
		||||
fail_unmap_regs_dma:
 | 
			
		||||
	iounmap(esp->dma_regs);
 | 
			
		||||
fail_unmap_regs:
 | 
			
		||||
	iounmap(esp->regs);
 | 
			
		||||
fail_unlink:
 | 
			
		||||
	scsi_host_put(host);
 | 
			
		||||
fail:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __devexit esp_sun3x_remove(struct platform_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct esp *esp = dev_get_drvdata(&dev->dev);
 | 
			
		||||
	unsigned int irq = esp->host->irq;
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	scsi_esp_unregister(esp);
 | 
			
		||||
 | 
			
		||||
	/* Disable interrupts.  */
 | 
			
		||||
	val = dma_read32(DMA_CSR);
 | 
			
		||||
	dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
 | 
			
		||||
 | 
			
		||||
	free_irq(irq, esp);
 | 
			
		||||
	dma_free_coherent(esp->dev, 16,
 | 
			
		||||
			  esp->command_block,
 | 
			
		||||
			  esp->command_block_dma);
 | 
			
		||||
 | 
			
		||||
	scsi_host_put(esp->host);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver esp_sun3x_driver = {
 | 
			
		||||
	.probe          = esp_sun3x_probe,
 | 
			
		||||
	.remove         = __devexit_p(esp_sun3x_remove),
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name   = "sun3x_esp",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init sun3x_esp_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return platform_driver_register(&esp_sun3x_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit sun3x_esp_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	platform_driver_unregister(&esp_sun3x_driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MODULE_DESCRIPTION("Sun3x ESP SCSI driver");
 | 
			
		||||
MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_VERSION(DRV_VERSION);
 | 
			
		||||
 | 
			
		||||
module_init(sun3x_esp_init);
 | 
			
		||||
module_exit(sun3x_esp_exit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue