gvp11.c 10.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2
#include <linux/types.h>
#include <linux/mm.h>
3
#include <linux/slab.h>
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/interrupt.h>

#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <linux/zorro.h>
#include <asm/irq.h>
#include <linux/spinlock.h>

#include "scsi.h"
#include <scsi/scsi_host.h>
#include "wd33c93.h"
#include "gvp11.h"

G
Geert Uytterhoeven 已提交
22
#include <linux/stat.h>
L
Linus Torvalds 已提交
23 24


G
Geert Uytterhoeven 已提交
25 26 27 28
#define DMA(ptr)	((gvp11_scsiregs *)((ptr)->base))
#define HDATA(ptr)	((struct WD33C93_hostdata *)((ptr)->hostdata))

static irqreturn_t gvp11_intr(int irq, void *_instance)
L
Linus Torvalds 已提交
29
{
G
Geert Uytterhoeven 已提交
30 31 32 33 34 35 36 37 38 39 40 41
	unsigned long flags;
	unsigned int status;
	struct Scsi_Host *instance = (struct Scsi_Host *)_instance;

	status = DMA(instance)->CNTR;
	if (!(status & GVP11_DMAC_INT_PENDING))
		return IRQ_NONE;

	spin_lock_irqsave(instance->host_lock, flags);
	wd33c93_intr(instance);
	spin_unlock_irqrestore(instance->host_lock, flags);
	return IRQ_HANDLED;
L
Linus Torvalds 已提交
42 43 44 45
}

static int gvp11_xfer_mask = 0;

G
Geert Uytterhoeven 已提交
46
void gvp11_setup(char *str, int *ints)
L
Linus Torvalds 已提交
47
{
G
Geert Uytterhoeven 已提交
48
	gvp11_xfer_mask = ints[1];
L
Linus Torvalds 已提交
49 50
}

51
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
L
Linus Torvalds 已提交
52
{
G
Geert Uytterhoeven 已提交
53 54 55 56
	unsigned short cntr = GVP11_DMAC_INT_ENABLE;
	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
	int bank_mask;
	static int scsi_alloc_out_of_range = 0;
L
Linus Torvalds 已提交
57

G
Geert Uytterhoeven 已提交
58 59 60 61 62 63 64 65 66 67 68 69
	/* use bounce buffer if the physical address is bad */
	if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
		HDATA(cmd->device->host)->dma_bounce_len =
			(cmd->SCp.this_residual + 511) & ~0x1ff;

		if (!scsi_alloc_out_of_range) {
			HDATA(cmd->device->host)->dma_bounce_buffer =
				kmalloc(HDATA(cmd->device->host)->dma_bounce_len,
					GFP_KERNEL);
			HDATA(cmd->device->host)->dma_buffer_pool =
				BUF_SCSI_ALLOCED;
		}
L
Linus Torvalds 已提交
70

G
Geert Uytterhoeven 已提交
71 72 73 74 75
		if (scsi_alloc_out_of_range ||
		    !HDATA(cmd->device->host)->dma_bounce_buffer) {
			HDATA(cmd->device->host)->dma_bounce_buffer =
				amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
						 "GVP II SCSI Bounce Buffer");
L
Linus Torvalds 已提交
76

G
Geert Uytterhoeven 已提交
77 78 79 80
			if (!HDATA(cmd->device->host)->dma_bounce_buffer) {
				HDATA(cmd->device->host)->dma_bounce_len = 0;
				return 1;
			}
L
Linus Torvalds 已提交
81

G
Geert Uytterhoeven 已提交
82 83 84
			HDATA(cmd->device->host)->dma_buffer_pool =
				BUF_CHIP_ALLOCED;
		}
L
Linus Torvalds 已提交
85

G
Geert Uytterhoeven 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
		/* check if the address of the bounce buffer is OK */
		addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);

		if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
			/* fall back to Chip RAM if address out of range */
			if (HDATA(cmd->device->host)->dma_buffer_pool ==
			    BUF_SCSI_ALLOCED) {
				kfree(HDATA(cmd->device->host)->dma_bounce_buffer);
				scsi_alloc_out_of_range = 1;
			} else {
				amiga_chip_free(HDATA(cmd->device->host)->dma_bounce_buffer);
			}

			HDATA(cmd->device->host)->dma_bounce_buffer =
				amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
						 "GVP II SCSI Bounce Buffer");

			if (!HDATA(cmd->device->host)->dma_bounce_buffer) {
				HDATA(cmd->device->host)->dma_bounce_len = 0;
				return 1;
			}

			addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
			HDATA(cmd->device->host)->dma_buffer_pool =
				BUF_CHIP_ALLOCED;
		}

		if (!dir_in) {
			/* copy to bounce buffer for a write */
			memcpy(HDATA(cmd->device->host)->dma_bounce_buffer,
			       cmd->SCp.ptr, cmd->SCp.this_residual);
		}
L
Linus Torvalds 已提交
118 119
	}

G
Geert Uytterhoeven 已提交
120 121 122
	/* setup dma direction */
	if (!dir_in)
		cntr |= GVP11_DMAC_DIR_WRITE;
L
Linus Torvalds 已提交
123

G
Geert Uytterhoeven 已提交
124 125
	HDATA(cmd->device->host)->dma_dir = dir_in;
	DMA(cmd->device->host)->CNTR = cntr;
L
Linus Torvalds 已提交
126

G
Geert Uytterhoeven 已提交
127 128
	/* setup DMA *physical* address */
	DMA(cmd->device->host)->ACR = addr;
L
Linus Torvalds 已提交
129

G
Geert Uytterhoeven 已提交
130 131 132 133 134 135 136
	if (dir_in) {
		/* invalidate any cache */
		cache_clear(addr, cmd->SCp.this_residual);
	} else {
		/* push any dirty cache */
		cache_push(addr, cmd->SCp.this_residual);
	}
L
Linus Torvalds 已提交
137

G
Geert Uytterhoeven 已提交
138 139
	if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
		DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
L
Linus Torvalds 已提交
140

G
Geert Uytterhoeven 已提交
141 142
	/* start DMA */
	DMA(cmd->device->host)->ST_DMA = 1;
L
Linus Torvalds 已提交
143

G
Geert Uytterhoeven 已提交
144 145
	/* return success */
	return 0;
L
Linus Torvalds 已提交
146 147
}

148 149
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
		     int status)
L
Linus Torvalds 已提交
150
{
G
Geert Uytterhoeven 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
	/* stop DMA */
	DMA(instance)->SP_DMA = 1;
	/* remove write bit from CONTROL bits */
	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;

	/* copy from a bounce buffer, if necessary */
	if (status && HDATA(instance)->dma_bounce_buffer) {
		if (HDATA(instance)->dma_dir && SCpnt)
			memcpy(SCpnt->SCp.ptr,
			       HDATA(instance)->dma_bounce_buffer,
			       SCpnt->SCp.this_residual);

		if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
			kfree(HDATA(instance)->dma_bounce_buffer);
		else
			amiga_chip_free(HDATA(instance)->dma_bounce_buffer);

		HDATA(instance)->dma_bounce_buffer = NULL;
		HDATA(instance)->dma_bounce_len = 0;
	}
L
Linus Torvalds 已提交
171 172 173 174
}

#define CHECK_WD33C93

175
int __init gvp11_detect(struct scsi_host_template *tpnt)
L
Linus Torvalds 已提交
176
{
G
Geert Uytterhoeven 已提交
177 178 179 180 181 182 183 184
	static unsigned char called = 0;
	struct Scsi_Host *instance;
	unsigned long address;
	unsigned int epc;
	struct zorro_dev *z = NULL;
	unsigned int default_dma_xfer_mask;
	wd33c93_regs regs;
	int num_gvp11 = 0;
L
Linus Torvalds 已提交
185
#ifdef CHECK_WD33C93
G
Geert Uytterhoeven 已提交
186 187 188
	volatile unsigned char *sasr_3393, *scmd_3393;
	unsigned char save_sasr;
	unsigned char q, qq;
L
Linus Torvalds 已提交
189 190
#endif

G
Geert Uytterhoeven 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
	if (!MACH_IS_AMIGA || called)
		return 0;
	called = 1;

	tpnt->proc_name = "GVP11";
	tpnt->proc_info = &wd33c93_proc_info;

	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
		/*
		 * This should (hopefully) be the correct way to identify
		 * all the different GVP SCSI controllers (except for the
		 * SERIES I though).
		 */

		if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
		    z->id == ZORRO_PROD_GVP_SERIES_II)
			default_dma_xfer_mask = ~0x00ffffff;
		else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
			 z->id == ZORRO_PROD_GVP_A530_SCSI ||
			 z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
			default_dma_xfer_mask = ~0x01ffffff;
		else if (z->id == ZORRO_PROD_GVP_A1291 ||
			 z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
			default_dma_xfer_mask = ~0x07ffffff;
		else
			continue;

		/*
		 * Rumors state that some GVP ram boards use the same product
		 * code as the SCSI controllers. Therefore if the board-size
		 * is not 64KB we asume it is a ram board and bail out.
		 */
		if (z->resource.end - z->resource.start != 0xffff)
			continue;

		address = z->resource.start;
		if (!request_mem_region(address, 256, "wd33c93"))
			continue;
L
Linus Torvalds 已提交
229 230 231

#ifdef CHECK_WD33C93

G
Geert Uytterhoeven 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
		/*
		 * These darn GVP boards are a problem - it can be tough to tell
		 * whether or not they include a SCSI controller. This is the
		 * ultimate Yet-Another-GVP-Detection-Hack in that it actually
		 * probes for a WD33c93 chip: If we find one, it's extremely
		 * likely that this card supports SCSI, regardless of Product_
		 * Code, Board_Size, etc.
		 */

		/* Get pointers to the presumed register locations and save contents */

		sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
		scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
		save_sasr = *sasr_3393;

		/* First test the AuxStatus Reg */

		q = *sasr_3393;	/* read it */
		if (q & 0x08)	/* bit 3 should always be clear */
			goto release;
		*sasr_3393 = WD_AUXILIARY_STATUS;	/* setup indirect address */
		if (*sasr_3393 == WD_AUXILIARY_STATUS) {	/* shouldn't retain the write */
			*sasr_3393 = save_sasr;	/* Oops - restore this byte */
			goto release;
L
Linus Torvalds 已提交
256
		}
G
Geert Uytterhoeven 已提交
257 258 259
		if (*sasr_3393 != q) {	/* should still read the same */
			*sasr_3393 = save_sasr;	/* Oops - restore this byte */
			goto release;
L
Linus Torvalds 已提交
260
		}
G
Geert Uytterhoeven 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
		if (*scmd_3393 != q)	/* and so should the image at 0x1f */
			goto release;

		/*
		 * Ok, we probably have a wd33c93, but let's check a few other places
		 * for good measure. Make sure that this works for both 'A and 'B
		 * chip versions.
		 */

		*sasr_3393 = WD_SCSI_STATUS;
		q = *scmd_3393;
		*sasr_3393 = WD_SCSI_STATUS;
		*scmd_3393 = ~q;
		*sasr_3393 = WD_SCSI_STATUS;
		qq = *scmd_3393;
		*sasr_3393 = WD_SCSI_STATUS;
		*scmd_3393 = q;
		if (qq != q)	/* should be read only */
			goto release;
		*sasr_3393 = 0x1e;	/* this register is unimplemented */
		q = *scmd_3393;
		*sasr_3393 = 0x1e;
		*scmd_3393 = ~q;
		*sasr_3393 = 0x1e;
		qq = *scmd_3393;
		*sasr_3393 = 0x1e;
		*scmd_3393 = q;
		if (qq != q || qq != 0xff)	/* should be read only, all 1's */
			goto release;
		*sasr_3393 = WD_TIMEOUT_PERIOD;
		q = *scmd_3393;
		*sasr_3393 = WD_TIMEOUT_PERIOD;
		*scmd_3393 = ~q;
		*sasr_3393 = WD_TIMEOUT_PERIOD;
		qq = *scmd_3393;
		*sasr_3393 = WD_TIMEOUT_PERIOD;
		*scmd_3393 = q;
		if (qq != (~q & 0xff))	/* should be read/write */
			goto release;
L
Linus Torvalds 已提交
300 301
#endif

G
Geert Uytterhoeven 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
		instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
		if (instance == NULL)
			goto release;
		instance->base = ZTWO_VADDR(address);
		instance->irq = IRQ_AMIGA_PORTS;
		instance->unique_id = z->slotaddr;

		if (gvp11_xfer_mask)
			HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask;
		else
			HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask;

		DMA(instance)->secret2 = 1;
		DMA(instance)->secret1 = 0;
		DMA(instance)->secret3 = 15;
		while (DMA(instance)->CNTR & GVP11_DMAC_BUSY)
			;
		DMA(instance)->CNTR = 0;

		DMA(instance)->BANK = 0;

		epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);

		/*
		 * Check for 14MHz SCSI clock
		 */
		regs.SASR = &(DMA(instance)->SASR);
		regs.SCMD = &(DMA(instance)->SCMD);
		HDATA(instance)->no_sync = 0xff;
		HDATA(instance)->fast = 0;
		HDATA(instance)->dma_mode = CTRL_DMA;
		wd33c93_init(instance, regs, dma_setup, dma_stop,
			     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
						     : WD33C93_FS_12_15);

		if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
				"GVP11 SCSI", instance))
			goto unregister;
		DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
		num_gvp11++;
		continue;
L
Linus Torvalds 已提交
343

344
unregister:
G
Geert Uytterhoeven 已提交
345
		scsi_unregister(instance);
L
Linus Torvalds 已提交
346
release:
G
Geert Uytterhoeven 已提交
347 348
		release_mem_region(address, 256);
	}
L
Linus Torvalds 已提交
349

G
Geert Uytterhoeven 已提交
350
	return num_gvp11;
L
Linus Torvalds 已提交
351 352
}

353
static int gvp11_bus_reset(struct scsi_cmnd *cmd)
L
Linus Torvalds 已提交
354 355
{
	/* FIXME perform bus-specific reset */
356

357 358 359 360
	/* FIXME 2: shouldn't we no-op this function (return
	   FAILED), and fall back to host reset function,
	   wd33c93_host_reset ? */

361
	spin_lock_irq(cmd->device->host->host_lock);
L
Linus Torvalds 已提交
362
	wd33c93_host_reset(cmd);
363 364
	spin_unlock_irq(cmd->device->host->host_lock);

L
Linus Torvalds 已提交
365 366 367 368 369 370 371 372
	return SUCCESS;
}


#define HOSTS_C

#include "gvp11.h"

373
static struct scsi_host_template driver_template = {
L
Linus Torvalds 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	.proc_name		= "GVP11",
	.name			= "GVP Series II SCSI",
	.detect			= gvp11_detect,
	.release		= gvp11_release,
	.queuecommand		= wd33c93_queuecommand,
	.eh_abort_handler	= wd33c93_abort,
	.eh_bus_reset_handler	= gvp11_bus_reset,
	.eh_host_reset_handler	= wd33c93_host_reset,
	.can_queue		= CAN_QUEUE,
	.this_id		= 7,
	.sg_tablesize		= SG_ALL,
	.cmd_per_lun		= CMD_PER_LUN,
	.use_clustering		= DISABLE_CLUSTERING
};


#include "scsi_module.c"

int gvp11_release(struct Scsi_Host *instance)
{
#ifdef MODULE
G
Geert Uytterhoeven 已提交
395 396 397
	DMA(instance)->CNTR = 0;
	release_mem_region(ZTWO_PADDR(instance->base), 256);
	free_irq(IRQ_AMIGA_PORTS, instance);
L
Linus Torvalds 已提交
398
#endif
G
Geert Uytterhoeven 已提交
399
	return 1;
L
Linus Torvalds 已提交
400 401 402
}

MODULE_LICENSE("GPL");