gvp11.c 10.2 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


25 26
#define CHECK_WD33C93

27
static irqreturn_t gvp11_intr(int irq, void *data)
L
Linus Torvalds 已提交
28
{
29
	struct Scsi_Host *instance = data;
30
	struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
31
	unsigned int status = regs->CNTR;
G
Geert Uytterhoeven 已提交
32 33 34 35 36 37 38 39 40
	unsigned long flags;

	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 已提交
41 42 43 44
}

static int gvp11_xfer_mask = 0;

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

50
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
L
Linus Torvalds 已提交
51
{
52 53
	struct Scsi_Host *instance = cmd->device->host;
	struct WD33C93_hostdata *hdata = shost_priv(instance);
54
	struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
G
Geert Uytterhoeven 已提交
55 56 57 58
	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 已提交
59

G
Geert Uytterhoeven 已提交
60
	/* use bounce buffer if the physical address is bad */
61 62
	if (addr & hdata->dma_xfer_mask) {
		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
G
Geert Uytterhoeven 已提交
63 64

		if (!scsi_alloc_out_of_range) {
65 66 67
			hdata->dma_bounce_buffer =
				kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
			hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
G
Geert Uytterhoeven 已提交
68
		}
L
Linus Torvalds 已提交
69

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

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

81
			hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
G
Geert Uytterhoeven 已提交
82
		}
L
Linus Torvalds 已提交
83

G
Geert Uytterhoeven 已提交
84
		/* check if the address of the bounce buffer is OK */
85
		addr = virt_to_bus(hdata->dma_bounce_buffer);
G
Geert Uytterhoeven 已提交
86

87
		if (addr & hdata->dma_xfer_mask) {
G
Geert Uytterhoeven 已提交
88
			/* fall back to Chip RAM if address out of range */
89 90
			if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
				kfree(hdata->dma_bounce_buffer);
G
Geert Uytterhoeven 已提交
91 92
				scsi_alloc_out_of_range = 1;
			} else {
93
				amiga_chip_free(hdata->dma_bounce_buffer);
G
Geert Uytterhoeven 已提交
94 95
			}

96 97
			hdata->dma_bounce_buffer =
				amiga_chip_alloc(hdata->dma_bounce_len,
G
Geert Uytterhoeven 已提交
98 99
						 "GVP II SCSI Bounce Buffer");

100 101
			if (!hdata->dma_bounce_buffer) {
				hdata->dma_bounce_len = 0;
G
Geert Uytterhoeven 已提交
102 103 104
				return 1;
			}

105 106
			addr = virt_to_bus(hdata->dma_bounce_buffer);
			hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
G
Geert Uytterhoeven 已提交
107 108 109 110
		}

		if (!dir_in) {
			/* copy to bounce buffer for a write */
111 112
			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
			       cmd->SCp.this_residual);
G
Geert Uytterhoeven 已提交
113
		}
L
Linus Torvalds 已提交
114 115
	}

G
Geert Uytterhoeven 已提交
116 117 118
	/* setup dma direction */
	if (!dir_in)
		cntr |= GVP11_DMAC_DIR_WRITE;
L
Linus Torvalds 已提交
119

120
	hdata->dma_dir = dir_in;
121
	regs->CNTR = cntr;
L
Linus Torvalds 已提交
122

G
Geert Uytterhoeven 已提交
123
	/* setup DMA *physical* address */
124
	regs->ACR = addr;
L
Linus Torvalds 已提交
125

G
Geert Uytterhoeven 已提交
126 127 128 129 130 131 132
	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 已提交
133

134 135
	bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
	if (bank_mask)
136
		regs->BANK = bank_mask & (addr >> 18);
L
Linus Torvalds 已提交
137

G
Geert Uytterhoeven 已提交
138
	/* start DMA */
139
	regs->ST_DMA = 1;
L
Linus Torvalds 已提交
140

G
Geert Uytterhoeven 已提交
141 142
	/* return success */
	return 0;
L
Linus Torvalds 已提交
143 144
}

145 146
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
		     int status)
L
Linus Torvalds 已提交
147
{
148
	struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
149 150
	struct WD33C93_hostdata *hdata = shost_priv(instance);

G
Geert Uytterhoeven 已提交
151
	/* stop DMA */
152
	regs->SP_DMA = 1;
G
Geert Uytterhoeven 已提交
153
	/* remove write bit from CONTROL bits */
154
	regs->CNTR = GVP11_DMAC_INT_ENABLE;
G
Geert Uytterhoeven 已提交
155 156

	/* copy from a bounce buffer, if necessary */
157 158 159
	if (status && hdata->dma_bounce_buffer) {
		if (hdata->dma_dir && SCpnt)
			memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
G
Geert Uytterhoeven 已提交
160 161
			       SCpnt->SCp.this_residual);

162 163
		if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
			kfree(hdata->dma_bounce_buffer);
G
Geert Uytterhoeven 已提交
164
		else
165
			amiga_chip_free(hdata->dma_bounce_buffer);
G
Geert Uytterhoeven 已提交
166

167 168
		hdata->dma_bounce_buffer = NULL;
		hdata->dma_bounce_len = 0;
G
Geert Uytterhoeven 已提交
169
	}
L
Linus Torvalds 已提交
170 171
}

172
static int __init check_wd33c93(struct gvp11_scsiregs *regs)
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 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 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
{
#ifdef CHECK_WD33C93
	volatile unsigned char *sasr_3393, *scmd_3393;
	unsigned char save_sasr;
	unsigned char q, qq;

	/*
	 * 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 = &regs->SASR;
	scmd_3393 = &regs->SCMD;
	save_sasr = *sasr_3393;

	/* First test the AuxStatus Reg */

	q = *sasr_3393;	/* read it */
	if (q & 0x08)	/* bit 3 should always be clear */
		return -ENODEV;
	*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 */
		return -ENODEV;
	}
	if (*sasr_3393 != q) {	/* should still read the same */
		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
		return -ENODEV;
	}
	if (*scmd_3393 != q)	/* and so should the image at 0x1f */
		return -ENODEV;

	/*
	 * 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 */
		return -ENODEV;
	*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 */
		return -ENODEV;
	*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 */
		return -ENODEV;
#endif /* CHECK_WD33C93 */

	return 0;
}
L
Linus Torvalds 已提交
251

252
int __init gvp11_detect(struct scsi_host_template *tpnt)
L
Linus Torvalds 已提交
253
{
G
Geert Uytterhoeven 已提交
254 255 256 257 258 259
	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;
260
	struct WD33C93_hostdata *hdata;
261
	struct gvp11_scsiregs *regs;
262
	wd33c93_regs wdregs;
G
Geert Uytterhoeven 已提交
263
	int num_gvp11 = 0;
L
Linus Torvalds 已提交
264

G
Geert Uytterhoeven 已提交
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 300 301 302
	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 已提交
303

304
		regs = (struct gvp11_scsiregs *)(ZTWO_VADDR(address));
305
		if (check_wd33c93(regs))
G
Geert Uytterhoeven 已提交
306
			goto release;
L
Linus Torvalds 已提交
307

G
Geert Uytterhoeven 已提交
308 309 310 311 312 313 314
		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;

315
		hdata = shost_priv(instance);
G
Geert Uytterhoeven 已提交
316
		if (gvp11_xfer_mask)
317
			hdata->dma_xfer_mask = gvp11_xfer_mask;
G
Geert Uytterhoeven 已提交
318
		else
319
			hdata->dma_xfer_mask = default_dma_xfer_mask;
G
Geert Uytterhoeven 已提交
320

321 322 323 324
		regs->secret2 = 1;
		regs->secret1 = 0;
		regs->secret3 = 15;
		while (regs->CNTR & GVP11_DMAC_BUSY)
G
Geert Uytterhoeven 已提交
325
			;
326
		regs->CNTR = 0;
G
Geert Uytterhoeven 已提交
327

328
		regs->BANK = 0;
G
Geert Uytterhoeven 已提交
329 330 331 332 333 334

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

		/*
		 * Check for 14MHz SCSI clock
		 */
335 336
		wdregs.SASR = &regs->SASR;
		wdregs.SCMD = &regs->SCMD;
337 338 339
		hdata->no_sync = 0xff;
		hdata->fast = 0;
		hdata->dma_mode = CTRL_DMA;
340
		wd33c93_init(instance, wdregs, dma_setup, dma_stop,
G
Geert Uytterhoeven 已提交
341 342 343 344 345 346
			     (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;
347
		regs->CNTR = GVP11_DMAC_INT_ENABLE;
G
Geert Uytterhoeven 已提交
348 349
		num_gvp11++;
		continue;
L
Linus Torvalds 已提交
350

351
unregister:
G
Geert Uytterhoeven 已提交
352
		scsi_unregister(instance);
L
Linus Torvalds 已提交
353
release:
G
Geert Uytterhoeven 已提交
354 355
		release_mem_region(address, 256);
	}
L
Linus Torvalds 已提交
356

G
Geert Uytterhoeven 已提交
357
	return num_gvp11;
L
Linus Torvalds 已提交
358 359
}

360
static int gvp11_bus_reset(struct scsi_cmnd *cmd)
L
Linus Torvalds 已提交
361 362
{
	/* FIXME perform bus-specific reset */
363

364 365 366 367
	/* FIXME 2: shouldn't we no-op this function (return
	   FAILED), and fall back to host reset function,
	   wd33c93_host_reset ? */

368
	spin_lock_irq(cmd->device->host->host_lock);
L
Linus Torvalds 已提交
369
	wd33c93_host_reset(cmd);
370 371
	spin_unlock_irq(cmd->device->host->host_lock);

L
Linus Torvalds 已提交
372 373 374 375 376 377 378 379
	return SUCCESS;
}


#define HOSTS_C

#include "gvp11.h"

380
static struct scsi_host_template driver_template = {
L
Linus Torvalds 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
	.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
402
	struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
403 404

	regs->CNTR = 0;
G
Geert Uytterhoeven 已提交
405 406
	release_mem_region(ZTWO_PADDR(instance->base), 256);
	free_irq(IRQ_AMIGA_PORTS, instance);
L
Linus Torvalds 已提交
407
#endif
G
Geert Uytterhoeven 已提交
408
	return 1;
L
Linus Torvalds 已提交
409 410 411
}

MODULE_LICENSE("GPL");