patch-2.3.48 linux/drivers/scsi/dec_esp.c

Next file: linux/drivers/scsi/dec_esp.h
Previous file: linux/drivers/scsi/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/dec_esp.c linux/drivers/scsi/dec_esp.c
@@ -1,7 +1,9 @@
 /*
  * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations
+ *            and TURBOchannel PMAZ-A cards
  *
  * TURBOchannel changes by Harald Koerfgen
+ * PMAZ-A support by David Airlie
  *
  * based on jazz_esp.c:
  * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
@@ -38,21 +40,43 @@
 
 static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
 static void dma_drain(struct NCR_ESP *esp);
+static void pmaz_dma_drain(struct NCR_ESP *esp);
 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 void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void pmaz_dma_ints_off(struct NCR_ESP *esp);
+static void pmaz_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 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 pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp);
+// static void pmaz_dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp);
 static void dma_advance_sg(Scsi_Cmnd * sp);
 
+#define TC_ESP_RAM_SIZE 0x20000
+#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1))
+#define ESP_NCMD 7
+
+#define TC_ESP_DMAR_MASK  0x1ffff
+#define TC_ESP_DMAR_WRITE 0x80000000
+#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK)
+
+volatile unsigned char *scsi_pmaz_dma_ptrs_tc[ESP_NCMD];
+unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD];
+unsigned char scsi_cur_buff = 1;	/* Leave space for command buffer */
+__u32 esp_virt_buffer;
+int scsi_current_length = 0;
 
 volatile unsigned char cmd_buffer[16];
+volatile unsigned char pmaz_cmd_buffer[16];
 				/* This is where all commands are put
 				 * before they are trasfered to the ESP chip
 				 * via PIO.
@@ -65,6 +89,8 @@
 volatile unsigned long *scsi_sdr0;
 volatile unsigned long *scsi_sdr1;
 
+volatile int *scsi_pmaz_dma_ptr_tc;
+
 static void scsi_dma_int(int, void *, struct pt_regs *);
 
 /***************************************************************** Detection */
@@ -72,6 +98,9 @@
 {
     struct NCR_ESP *esp;
     struct ConfigDev *esp_dev;
+	int slot, i;
+	unsigned long mem_start;
+	volatile unsigned char *buffer;
 
 	if (IOASIC) {
 	esp_dev = 0;
@@ -143,21 +172,88 @@
 		request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA",
 			    NULL);
 
-	/*
-	 * FIXME, look if the scsi id is availabe from NVRAM
-	 */
 	esp->scsi_id = 7;
 		
 	/* Check for differential SCSI-bus */
-	/* What is this stuff? */
 	esp->diff = 0;
 
 	esp_initialize(esp);
 	
+	}
+
+	if (TURBOCHANNEL) {
+		while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
+			claim_tc_card(slot);
+			mem_start = get_tc_base_addr(slot);
+
+			esp_dev = 0;
+			esp = esp_allocate(tpnt, (void *) esp_dev);
+
+			esp->dregs = 0;
+			esp->eregs = (struct ESP_regs *) (mem_start + DEC_SCSI_SREG);
+			esp->do_pio_cmds = 1;
+
+			/* Set the command buffer */
+			esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
+
+			/* get virtual dma address for command buffer */
+			esp->esp_command_dvma = (__u32) KSEG0ADDR((volatile unsigned char *) pmaz_cmd_buffer);
+
+			buffer = (volatile unsigned char *) (mem_start + DEC_SCSI_SRAM);
+
+			scsi_pmaz_dma_ptr_tc = (volatile int *) (mem_start + DEC_SCSI_DMAREG);
+
+			for (i = 0; i < ESP_NCMD; i++) {
+				scsi_pmaz_dma_ptrs_tc[i] = (volatile unsigned char *) (buffer + ESP_TGT_DMA_SIZE * i);
+			}
+
+			scsi_pmaz_dma_buff_used[0] = 1;
+
+			esp->cfreq = get_tc_speed();
+
+			esp->irq = get_tc_irq_nr(slot);
+
+			/* 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 = &pmaz_dma_init_read;
+			esp->dma_init_write = &pmaz_dma_init_write;
+			esp->dma_ints_off = &pmaz_dma_ints_off;
+			esp->dma_ints_on = &pmaz_dma_ints_on;
+			esp->dma_irq_p = &dma_irq_p;
+			esp->dma_ports_p = &dma_ports_p;
+			esp->dma_setup = &pmaz_dma_setup;
+
+			/* Optional functions */
+			esp->dma_barrier = 0;
+			esp->dma_drain = &pmaz_dma_drain;
+			esp->dma_invalidate = 0;
+			esp->dma_irq_entry = 0;
+			esp->dma_irq_exit = 0;
+			esp->dma_poll = 0;
+			esp->dma_reset = 0;
+			esp->dma_led_off = 0;
+			esp->dma_led_on = 0;
+
+			esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+			esp->dma_mmu_get_scsi_sgl = 0;
+			esp->dma_mmu_release_scsi_one = 0;
+			esp->dma_mmu_release_scsi_sgl = 0;
+			esp->dma_advance_sg = 0;
+
+			request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ-AA", NULL);
+			esp->scsi_id = 7;
+			esp->diff = 0;
+			esp_initialize(esp);
+		}
+	}
+
+	if(nesps) {
 		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;
-    }
+	} else
     return 0;
 }
 
@@ -172,18 +268,18 @@
 		*scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3;
 		*isr &= ~SCSI_PTR_LOADED;
 	} else {
-		printk("Got unexpected SCSI DMA Interrupt! < ");
 		if (*isr & SCSI_PAGOVRRUN)
-			printk("SCSI_PAGOVRRUN ");
-		if (*isr & SCSI_DMA_MEMRDERR)
+			*isr &= ~SCSI_PAGOVRRUN;
+		if (*isr & SCSI_DMA_MEMRDERR) {
+			printk("Got unexpected SCSI DMA Interrupt! < ");
 			printk("SCSI_DMA_MEMRDERR ");
 		printk(">\n");
-//		panic("stop");
-		*isr &= ~(SCSI_PAGOVRRUN || SCSI_DMA_MEMRDERR);
+			*isr &= ~SCSI_DMA_MEMRDERR;
+		}
 	}
 
 	/*
-	 * This driver will only work on IOASIC machines
+	 * This routine will only work on IOASIC machines
 	 * so we can avoid an indirect function call here
 	 * and flush the writeback buffer the fast way
 	 */
@@ -198,13 +294,13 @@
 
 static void dma_drain(struct NCR_ESP *esp)
 {
-	unsigned long nw;
+	unsigned long nw = *scsi_scr;
 	unsigned short *p = KSEG1ADDR((unsigned short *) ((*scsi_dma_ptr) >> 3));
 
     /*
 	 * Is there something in the dma buffers left?
      */
-	if (nw = *scsi_scr) {
+	if (nw) {
 		switch (nw) {
 		case 1:
 			*p = (unsigned short) *scsi_sdr0;
@@ -225,6 +321,12 @@
 	}
 }
 
+static void pmaz_dma_drain(struct NCR_ESP *esp)
+{
+	memcpy((volatile void *) (KSEG0ADDR(esp_virt_buffer)),
+		(void *) scsi_pmaz_dma_ptrs_tc[scsi_cur_buff], scsi_current_length);
+}
+
 static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp)
 {
 	return sp->SCp.this_residual;;
@@ -298,6 +400,33 @@
 	enable_irq(SCSI_DMA_INT);
 }
 
+static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+
+	if (length > ESP_TGT_DMA_SIZE)
+		length = ESP_TGT_DMA_SIZE;
+
+	*scsi_pmaz_dma_ptr_tc = TC_ESP_DMA_ADDR(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff]);
+	esp_virt_buffer = vaddress;
+	scsi_current_length = length;
+}
+
+static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	memcpy(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff], KSEG0ADDR((void *) vaddress), length);
+
+	*scsi_pmaz_dma_ptr_tc = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff]);
+
+}
+
+static void pmaz_dma_ints_off(struct NCR_ESP *esp)
+{
+}
+
+static void pmaz_dma_ints_on(struct NCR_ESP *esp)
+{
+}
+
 static int dma_irq_p(struct NCR_ESP *esp)
 {
     return (esp->eregs->esp_status & ESP_STAT_INTR);
@@ -322,6 +451,34 @@
     } else {
 	dma_init_write(esp, addr, count);
     }
+}
+
+static void pmaz_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) {
+		pmaz_dma_init_read(esp, addr, count);
+	} else {
+		pmaz_dma_init_write(esp, addr, count);
+	}
+}
+
+static void pmaz_dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
+{
+	int x;
+	for (x = 1; x < 6; x++)
+		if (sp->SCp.have_data_in == PHYSADDR(scsi_pmaz_dma_ptrs_tc[x]))
+			scsi_pmaz_dma_buff_used[x] = 0;
+}
+
+
+static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
+{
+	sp->SCp.have_data_in = (int) sp->SCp.ptr =
+	    (char *) KSEG0ADDR((sp->request_buffer));
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)