162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <linux/types.h>
362306a36Sopenharmony_ci#include <linux/init.h>
462306a36Sopenharmony_ci#include <linux/interrupt.h>
562306a36Sopenharmony_ci#include <linux/mm.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/spinlock.h>
862306a36Sopenharmony_ci#include <linux/zorro.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/page.h>
1262306a36Sopenharmony_ci#include <asm/amigaints.h>
1362306a36Sopenharmony_ci#include <asm/amigahw.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <scsi/scsi.h>
1662306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
1762306a36Sopenharmony_ci#include <scsi/scsi_device.h>
1862306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
1962306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
2062306a36Sopenharmony_ci#include "wd33c93.h"
2162306a36Sopenharmony_ci#include "gvp11.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define CHECK_WD33C93
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct gvp11_hostdata {
2762306a36Sopenharmony_ci	struct WD33C93_hostdata wh;
2862306a36Sopenharmony_ci	struct gvp11_scsiregs *regs;
2962306a36Sopenharmony_ci	struct device *dev;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define DMA_DIR(d)   ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)
3362306a36Sopenharmony_ci#define TO_DMA_MASK(m)	(~((unsigned long long)m & 0xffffffff))
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic irqreturn_t gvp11_intr(int irq, void *data)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct Scsi_Host *instance = data;
3862306a36Sopenharmony_ci	struct gvp11_hostdata *hdata = shost_priv(instance);
3962306a36Sopenharmony_ci	unsigned int status = hdata->regs->CNTR;
4062306a36Sopenharmony_ci	unsigned long flags;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (!(status & GVP11_DMAC_INT_PENDING))
4362306a36Sopenharmony_ci		return IRQ_NONE;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	spin_lock_irqsave(instance->host_lock, flags);
4662306a36Sopenharmony_ci	wd33c93_intr(instance);
4762306a36Sopenharmony_ci	spin_unlock_irqrestore(instance->host_lock, flags);
4862306a36Sopenharmony_ci	return IRQ_HANDLED;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int gvp11_xfer_mask = 0;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int dma_setup(struct scsi_cmnd *cmd, int dir_in)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd);
5662306a36Sopenharmony_ci	unsigned long len = scsi_pointer->this_residual;
5762306a36Sopenharmony_ci	struct Scsi_Host *instance = cmd->device->host;
5862306a36Sopenharmony_ci	struct gvp11_hostdata *hdata = shost_priv(instance);
5962306a36Sopenharmony_ci	struct WD33C93_hostdata *wh = &hdata->wh;
6062306a36Sopenharmony_ci	struct gvp11_scsiregs *regs = hdata->regs;
6162306a36Sopenharmony_ci	unsigned short cntr = GVP11_DMAC_INT_ENABLE;
6262306a36Sopenharmony_ci	dma_addr_t addr;
6362306a36Sopenharmony_ci	int bank_mask;
6462306a36Sopenharmony_ci	static int scsi_alloc_out_of_range = 0;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	addr = dma_map_single(hdata->dev, scsi_pointer->ptr,
6762306a36Sopenharmony_ci			      len, DMA_DIR(dir_in));
6862306a36Sopenharmony_ci	if (dma_mapping_error(hdata->dev, addr)) {
6962306a36Sopenharmony_ci		dev_warn(hdata->dev, "cannot map SCSI data block %p\n",
7062306a36Sopenharmony_ci			 scsi_pointer->ptr);
7162306a36Sopenharmony_ci		return 1;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci	scsi_pointer->dma_handle = addr;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* use bounce buffer if the physical address is bad */
7662306a36Sopenharmony_ci	if (addr & wh->dma_xfer_mask) {
7762306a36Sopenharmony_ci		/* drop useless mapping */
7862306a36Sopenharmony_ci		dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,
7962306a36Sopenharmony_ci				 scsi_pointer->this_residual,
8062306a36Sopenharmony_ci				 DMA_DIR(dir_in));
8162306a36Sopenharmony_ci		scsi_pointer->dma_handle = (dma_addr_t) NULL;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		if (!scsi_alloc_out_of_range) {
8662306a36Sopenharmony_ci			wh->dma_bounce_buffer =
8762306a36Sopenharmony_ci				kmalloc(wh->dma_bounce_len, GFP_KERNEL);
8862306a36Sopenharmony_ci			wh->dma_buffer_pool = BUF_SCSI_ALLOCED;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		if (scsi_alloc_out_of_range ||
9262306a36Sopenharmony_ci		    !wh->dma_bounce_buffer) {
9362306a36Sopenharmony_ci			wh->dma_bounce_buffer =
9462306a36Sopenharmony_ci				amiga_chip_alloc(wh->dma_bounce_len,
9562306a36Sopenharmony_ci						 "GVP II SCSI Bounce Buffer");
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci			if (!wh->dma_bounce_buffer) {
9862306a36Sopenharmony_ci				wh->dma_bounce_len = 0;
9962306a36Sopenharmony_ci				return 1;
10062306a36Sopenharmony_ci			}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci			wh->dma_buffer_pool = BUF_CHIP_ALLOCED;
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		if (!dir_in) {
10662306a36Sopenharmony_ci			/* copy to bounce buffer for a write */
10762306a36Sopenharmony_ci			memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr,
10862306a36Sopenharmony_ci			       scsi_pointer->this_residual);
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) {
11262306a36Sopenharmony_ci		/* will flush/invalidate cache for us */
11362306a36Sopenharmony_ci			addr = dma_map_single(hdata->dev,
11462306a36Sopenharmony_ci					      wh->dma_bounce_buffer,
11562306a36Sopenharmony_ci					      wh->dma_bounce_len,
11662306a36Sopenharmony_ci					      DMA_DIR(dir_in));
11762306a36Sopenharmony_ci			/* can't map buffer; use PIO */
11862306a36Sopenharmony_ci			if (dma_mapping_error(hdata->dev, addr)) {
11962306a36Sopenharmony_ci				dev_warn(hdata->dev,
12062306a36Sopenharmony_ci					 "cannot map bounce buffer %p\n",
12162306a36Sopenharmony_ci					 wh->dma_bounce_buffer);
12262306a36Sopenharmony_ci				return 1;
12362306a36Sopenharmony_ci			}
12462306a36Sopenharmony_ci		}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		if (addr & wh->dma_xfer_mask) {
12762306a36Sopenharmony_ci			/* drop useless mapping */
12862306a36Sopenharmony_ci			dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,
12962306a36Sopenharmony_ci					 scsi_pointer->this_residual,
13062306a36Sopenharmony_ci					 DMA_DIR(dir_in));
13162306a36Sopenharmony_ci			/* fall back to Chip RAM if address out of range */
13262306a36Sopenharmony_ci			if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) {
13362306a36Sopenharmony_ci				kfree(wh->dma_bounce_buffer);
13462306a36Sopenharmony_ci				scsi_alloc_out_of_range = 1;
13562306a36Sopenharmony_ci			} else {
13662306a36Sopenharmony_ci				amiga_chip_free(wh->dma_bounce_buffer);
13762306a36Sopenharmony_ci			}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci			wh->dma_bounce_buffer =
14062306a36Sopenharmony_ci				amiga_chip_alloc(wh->dma_bounce_len,
14162306a36Sopenharmony_ci						 "GVP II SCSI Bounce Buffer");
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci			if (!wh->dma_bounce_buffer) {
14462306a36Sopenharmony_ci				wh->dma_bounce_len = 0;
14562306a36Sopenharmony_ci				return 1;
14662306a36Sopenharmony_ci			}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci			if (!dir_in) {
14962306a36Sopenharmony_ci				/* copy to bounce buffer for a write */
15062306a36Sopenharmony_ci				memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr,
15162306a36Sopenharmony_ci				       scsi_pointer->this_residual);
15262306a36Sopenharmony_ci			}
15362306a36Sopenharmony_ci			/* chip RAM can be mapped to phys. address directly */
15462306a36Sopenharmony_ci			addr = virt_to_phys(wh->dma_bounce_buffer);
15562306a36Sopenharmony_ci			/* no need to flush/invalidate cache */
15662306a36Sopenharmony_ci			wh->dma_buffer_pool = BUF_CHIP_ALLOCED;
15762306a36Sopenharmony_ci		}
15862306a36Sopenharmony_ci		/* finally, have OK mapping (punted for PIO else) */
15962306a36Sopenharmony_ci		scsi_pointer->dma_handle = addr;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* setup dma direction */
16462306a36Sopenharmony_ci	if (!dir_in)
16562306a36Sopenharmony_ci		cntr |= GVP11_DMAC_DIR_WRITE;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	wh->dma_dir = dir_in;
16862306a36Sopenharmony_ci	regs->CNTR = cntr;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* setup DMA *physical* address */
17162306a36Sopenharmony_ci	regs->ACR = addr;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* no more cache flush here - dma_map_single() takes care */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	bank_mask = (~wh->dma_xfer_mask >> 18) & 0x01c0;
17662306a36Sopenharmony_ci	if (bank_mask)
17762306a36Sopenharmony_ci		regs->BANK = bank_mask & (addr >> 18);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* start DMA */
18062306a36Sopenharmony_ci	regs->ST_DMA = 1;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* return success */
18362306a36Sopenharmony_ci	return 0;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
18762306a36Sopenharmony_ci		     int status)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt);
19062306a36Sopenharmony_ci	struct gvp11_hostdata *hdata = shost_priv(instance);
19162306a36Sopenharmony_ci	struct WD33C93_hostdata *wh = &hdata->wh;
19262306a36Sopenharmony_ci	struct gvp11_scsiregs *regs = hdata->regs;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* stop DMA */
19562306a36Sopenharmony_ci	regs->SP_DMA = 1;
19662306a36Sopenharmony_ci	/* remove write bit from CONTROL bits */
19762306a36Sopenharmony_ci	regs->CNTR = GVP11_DMAC_INT_ENABLE;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED)
20062306a36Sopenharmony_ci		dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,
20162306a36Sopenharmony_ci				 scsi_pointer->this_residual,
20262306a36Sopenharmony_ci				 DMA_DIR(wh->dma_dir));
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* copy from a bounce buffer, if necessary */
20562306a36Sopenharmony_ci	if (status && wh->dma_bounce_buffer) {
20662306a36Sopenharmony_ci		if (wh->dma_dir && SCpnt)
20762306a36Sopenharmony_ci			memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer,
20862306a36Sopenharmony_ci			       scsi_pointer->this_residual);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED)
21162306a36Sopenharmony_ci			kfree(wh->dma_bounce_buffer);
21262306a36Sopenharmony_ci		else
21362306a36Sopenharmony_ci			amiga_chip_free(wh->dma_bounce_buffer);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		wh->dma_bounce_buffer = NULL;
21662306a36Sopenharmony_ci		wh->dma_bounce_len = 0;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic const struct scsi_host_template gvp11_scsi_template = {
22162306a36Sopenharmony_ci	.module			= THIS_MODULE,
22262306a36Sopenharmony_ci	.name			= "GVP Series II SCSI",
22362306a36Sopenharmony_ci	.show_info		= wd33c93_show_info,
22462306a36Sopenharmony_ci	.write_info		= wd33c93_write_info,
22562306a36Sopenharmony_ci	.proc_name		= "GVP11",
22662306a36Sopenharmony_ci	.queuecommand		= wd33c93_queuecommand,
22762306a36Sopenharmony_ci	.eh_abort_handler	= wd33c93_abort,
22862306a36Sopenharmony_ci	.eh_host_reset_handler	= wd33c93_host_reset,
22962306a36Sopenharmony_ci	.can_queue		= CAN_QUEUE,
23062306a36Sopenharmony_ci	.this_id		= 7,
23162306a36Sopenharmony_ci	.sg_tablesize		= SG_ALL,
23262306a36Sopenharmony_ci	.cmd_per_lun		= CMD_PER_LUN,
23362306a36Sopenharmony_ci	.dma_boundary		= PAGE_SIZE - 1,
23462306a36Sopenharmony_ci	.cmd_size		= sizeof(struct scsi_pointer),
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int check_wd33c93(struct gvp11_scsiregs *regs)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci#ifdef CHECK_WD33C93
24062306a36Sopenharmony_ci	volatile unsigned char *sasr_3393, *scmd_3393;
24162306a36Sopenharmony_ci	unsigned char save_sasr;
24262306a36Sopenharmony_ci	unsigned char q, qq;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * These darn GVP boards are a problem - it can be tough to tell
24662306a36Sopenharmony_ci	 * whether or not they include a SCSI controller. This is the
24762306a36Sopenharmony_ci	 * ultimate Yet-Another-GVP-Detection-Hack in that it actually
24862306a36Sopenharmony_ci	 * probes for a WD33c93 chip: If we find one, it's extremely
24962306a36Sopenharmony_ci	 * likely that this card supports SCSI, regardless of Product_
25062306a36Sopenharmony_ci	 * Code, Board_Size, etc.
25162306a36Sopenharmony_ci	 */
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Get pointers to the presumed register locations and save contents */
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	sasr_3393 = &regs->SASR;
25662306a36Sopenharmony_ci	scmd_3393 = &regs->SCMD;
25762306a36Sopenharmony_ci	save_sasr = *sasr_3393;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* First test the AuxStatus Reg */
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	q = *sasr_3393;	/* read it */
26262306a36Sopenharmony_ci	if (q & 0x08)	/* bit 3 should always be clear */
26362306a36Sopenharmony_ci		return -ENODEV;
26462306a36Sopenharmony_ci	*sasr_3393 = WD_AUXILIARY_STATUS;	/* setup indirect address */
26562306a36Sopenharmony_ci	if (*sasr_3393 == WD_AUXILIARY_STATUS) {	/* shouldn't retain the write */
26662306a36Sopenharmony_ci		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
26762306a36Sopenharmony_ci		return -ENODEV;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	if (*sasr_3393 != q) {	/* should still read the same */
27062306a36Sopenharmony_ci		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
27162306a36Sopenharmony_ci		return -ENODEV;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	if (*scmd_3393 != q)	/* and so should the image at 0x1f */
27462306a36Sopenharmony_ci		return -ENODEV;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/*
27762306a36Sopenharmony_ci	 * Ok, we probably have a wd33c93, but let's check a few other places
27862306a36Sopenharmony_ci	 * for good measure. Make sure that this works for both 'A and 'B
27962306a36Sopenharmony_ci	 * chip versions.
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	*sasr_3393 = WD_SCSI_STATUS;
28362306a36Sopenharmony_ci	q = *scmd_3393;
28462306a36Sopenharmony_ci	*sasr_3393 = WD_SCSI_STATUS;
28562306a36Sopenharmony_ci	*scmd_3393 = ~q;
28662306a36Sopenharmony_ci	*sasr_3393 = WD_SCSI_STATUS;
28762306a36Sopenharmony_ci	qq = *scmd_3393;
28862306a36Sopenharmony_ci	*sasr_3393 = WD_SCSI_STATUS;
28962306a36Sopenharmony_ci	*scmd_3393 = q;
29062306a36Sopenharmony_ci	if (qq != q)	/* should be read only */
29162306a36Sopenharmony_ci		return -ENODEV;
29262306a36Sopenharmony_ci	*sasr_3393 = 0x1e;	/* this register is unimplemented */
29362306a36Sopenharmony_ci	q = *scmd_3393;
29462306a36Sopenharmony_ci	*sasr_3393 = 0x1e;
29562306a36Sopenharmony_ci	*scmd_3393 = ~q;
29662306a36Sopenharmony_ci	*sasr_3393 = 0x1e;
29762306a36Sopenharmony_ci	qq = *scmd_3393;
29862306a36Sopenharmony_ci	*sasr_3393 = 0x1e;
29962306a36Sopenharmony_ci	*scmd_3393 = q;
30062306a36Sopenharmony_ci	if (qq != q || qq != 0xff)	/* should be read only, all 1's */
30162306a36Sopenharmony_ci		return -ENODEV;
30262306a36Sopenharmony_ci	*sasr_3393 = WD_TIMEOUT_PERIOD;
30362306a36Sopenharmony_ci	q = *scmd_3393;
30462306a36Sopenharmony_ci	*sasr_3393 = WD_TIMEOUT_PERIOD;
30562306a36Sopenharmony_ci	*scmd_3393 = ~q;
30662306a36Sopenharmony_ci	*sasr_3393 = WD_TIMEOUT_PERIOD;
30762306a36Sopenharmony_ci	qq = *scmd_3393;
30862306a36Sopenharmony_ci	*sasr_3393 = WD_TIMEOUT_PERIOD;
30962306a36Sopenharmony_ci	*scmd_3393 = q;
31062306a36Sopenharmony_ci	if (qq != (~q & 0xff))	/* should be read/write */
31162306a36Sopenharmony_ci		return -ENODEV;
31262306a36Sopenharmony_ci#endif /* CHECK_WD33C93 */
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int gvp11_probe(struct zorro_dev *z, const struct zorro_device_id *ent)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct Scsi_Host *instance;
32062306a36Sopenharmony_ci	unsigned long address;
32162306a36Sopenharmony_ci	int error;
32262306a36Sopenharmony_ci	unsigned int epc;
32362306a36Sopenharmony_ci	unsigned int default_dma_xfer_mask;
32462306a36Sopenharmony_ci	struct gvp11_hostdata *hdata;
32562306a36Sopenharmony_ci	struct gvp11_scsiregs *regs;
32662306a36Sopenharmony_ci	wd33c93_regs wdregs;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	default_dma_xfer_mask = ent->driver_data;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (dma_set_mask_and_coherent(&z->dev,
33162306a36Sopenharmony_ci		TO_DMA_MASK(default_dma_xfer_mask))) {
33262306a36Sopenharmony_ci		dev_warn(&z->dev, "cannot use DMA mask %llx\n",
33362306a36Sopenharmony_ci			 TO_DMA_MASK(default_dma_xfer_mask));
33462306a36Sopenharmony_ci		return -ENODEV;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * Rumors state that some GVP ram boards use the same product
33962306a36Sopenharmony_ci	 * code as the SCSI controllers. Therefore if the board-size
34062306a36Sopenharmony_ci	 * is not 64KB we assume it is a ram board and bail out.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (zorro_resource_len(z) != 0x10000)
34362306a36Sopenharmony_ci		return -ENODEV;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	address = z->resource.start;
34662306a36Sopenharmony_ci	if (!request_mem_region(address, 256, "wd33c93"))
34762306a36Sopenharmony_ci		return -EBUSY;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	regs = ZTWO_VADDR(address);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	error = check_wd33c93(regs);
35262306a36Sopenharmony_ci	if (error)
35362306a36Sopenharmony_ci		goto fail_check_or_alloc;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	instance = scsi_host_alloc(&gvp11_scsi_template,
35662306a36Sopenharmony_ci				   sizeof(struct gvp11_hostdata));
35762306a36Sopenharmony_ci	if (!instance) {
35862306a36Sopenharmony_ci		error = -ENOMEM;
35962306a36Sopenharmony_ci		goto fail_check_or_alloc;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	instance->irq = IRQ_AMIGA_PORTS;
36362306a36Sopenharmony_ci	instance->unique_id = z->slotaddr;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	regs->secret2 = 1;
36662306a36Sopenharmony_ci	regs->secret1 = 0;
36762306a36Sopenharmony_ci	regs->secret3 = 15;
36862306a36Sopenharmony_ci	while (regs->CNTR & GVP11_DMAC_BUSY)
36962306a36Sopenharmony_ci		;
37062306a36Sopenharmony_ci	regs->CNTR = 0;
37162306a36Sopenharmony_ci	regs->BANK = 0;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	wdregs.SASR = &regs->SASR;
37462306a36Sopenharmony_ci	wdregs.SCMD = &regs->SCMD;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	hdata = shost_priv(instance);
37762306a36Sopenharmony_ci	if (gvp11_xfer_mask) {
37862306a36Sopenharmony_ci		hdata->wh.dma_xfer_mask = gvp11_xfer_mask;
37962306a36Sopenharmony_ci		if (dma_set_mask_and_coherent(&z->dev,
38062306a36Sopenharmony_ci			TO_DMA_MASK(gvp11_xfer_mask))) {
38162306a36Sopenharmony_ci			dev_warn(&z->dev, "cannot use DMA mask %llx\n",
38262306a36Sopenharmony_ci				 TO_DMA_MASK(gvp11_xfer_mask));
38362306a36Sopenharmony_ci			error = -ENODEV;
38462306a36Sopenharmony_ci			goto fail_check_or_alloc;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	} else
38762306a36Sopenharmony_ci		hdata->wh.dma_xfer_mask = default_dma_xfer_mask;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	hdata->wh.no_sync = 0xff;
39062306a36Sopenharmony_ci	hdata->wh.fast = 0;
39162306a36Sopenharmony_ci	hdata->wh.dma_mode = CTRL_DMA;
39262306a36Sopenharmony_ci	hdata->regs = regs;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * Check for 14MHz SCSI clock
39662306a36Sopenharmony_ci	 */
39762306a36Sopenharmony_ci	epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
39862306a36Sopenharmony_ci	wd33c93_init(instance, wdregs, dma_setup, dma_stop,
39962306a36Sopenharmony_ci		     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
40062306a36Sopenharmony_ci					     : WD33C93_FS_12_15);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	error = request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
40362306a36Sopenharmony_ci			    "GVP11 SCSI", instance);
40462306a36Sopenharmony_ci	if (error)
40562306a36Sopenharmony_ci		goto fail_irq;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	regs->CNTR = GVP11_DMAC_INT_ENABLE;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	error = scsi_add_host(instance, NULL);
41062306a36Sopenharmony_ci	if (error)
41162306a36Sopenharmony_ci		goto fail_host;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	zorro_set_drvdata(z, instance);
41462306a36Sopenharmony_ci	scsi_scan_host(instance);
41562306a36Sopenharmony_ci	return 0;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cifail_host:
41862306a36Sopenharmony_ci	free_irq(IRQ_AMIGA_PORTS, instance);
41962306a36Sopenharmony_cifail_irq:
42062306a36Sopenharmony_ci	scsi_host_put(instance);
42162306a36Sopenharmony_cifail_check_or_alloc:
42262306a36Sopenharmony_ci	release_mem_region(address, 256);
42362306a36Sopenharmony_ci	return error;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic void gvp11_remove(struct zorro_dev *z)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct Scsi_Host *instance = zorro_get_drvdata(z);
42962306a36Sopenharmony_ci	struct gvp11_hostdata *hdata = shost_priv(instance);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	hdata->regs->CNTR = 0;
43262306a36Sopenharmony_ci	scsi_remove_host(instance);
43362306a36Sopenharmony_ci	free_irq(IRQ_AMIGA_PORTS, instance);
43462306a36Sopenharmony_ci	scsi_host_put(instance);
43562306a36Sopenharmony_ci	release_mem_region(z->resource.start, 256);
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/*
43962306a36Sopenharmony_ci	 * This should (hopefully) be the correct way to identify
44062306a36Sopenharmony_ci	 * all the different GVP SCSI controllers (except for the
44162306a36Sopenharmony_ci	 * SERIES I though).
44262306a36Sopenharmony_ci	 */
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic struct zorro_device_id gvp11_zorro_tbl[] = {
44562306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_COMBO_030_R3_SCSI,	~0x00ffffff },
44662306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_SERIES_II,		~0x00ffffff },
44762306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_GFORCE_030_SCSI,	~0x01ffffff },
44862306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_A530_SCSI,		~0x01ffffff },
44962306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_COMBO_030_R4_SCSI,	~0x01ffffff },
45062306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_A1291,			~0x07ffffff },
45162306a36Sopenharmony_ci	{ ZORRO_PROD_GVP_GFORCE_040_SCSI_1,	~0x07ffffff },
45262306a36Sopenharmony_ci	{ 0 }
45362306a36Sopenharmony_ci};
45462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic struct zorro_driver gvp11_driver = {
45762306a36Sopenharmony_ci	.name		= "gvp11",
45862306a36Sopenharmony_ci	.id_table	= gvp11_zorro_tbl,
45962306a36Sopenharmony_ci	.probe		= gvp11_probe,
46062306a36Sopenharmony_ci	.remove		= gvp11_remove,
46162306a36Sopenharmony_ci};
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic int __init gvp11_init(void)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	return zorro_register_driver(&gvp11_driver);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_cimodule_init(gvp11_init);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic void __exit gvp11_exit(void)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	zorro_unregister_driver(&gvp11_driver);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_cimodule_exit(gvp11_exit);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ciMODULE_DESCRIPTION("GVP Series II SCSI");
47662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
477