summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/zalon.c
blob: f1e5cf8a17d9ed0ade8c143f0c928c48eeb4e220 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Zalon 53c7xx device driver.
 * By Richard Hirst (rhirst@linuxcare.com)
 */

#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/hardware.h>
#include <asm/io.h>

#include "../parisc/gsc.h"

#include "ncr53c8xx.h"

MODULE_AUTHOR("Richard Hirst");
MODULE_DESCRIPTION("Bluefish/Zalon 720 SCSI Driver");
MODULE_LICENSE("GPL");

#define GSC_SCSI_ZALON_OFFSET 0x800

#define IO_MODULE_EIM		(1*4)
#define IO_MODULE_DC_ADATA	(2*4)
#define IO_MODULE_II_CDATA	(3*4)
#define IO_MODULE_IO_COMMAND	(12*4)
#define IO_MODULE_IO_STATUS	(13*4)

#define IOSTATUS_RY		0x40
#define IOSTATUS_FE		0x80
#define IOIIDATA_SMINT5L	0x40000000
#define IOIIDATA_MINT5EN	0x20000000
#define IOIIDATA_PACKEN		0x10000000
#define IOIIDATA_PREFETCHEN	0x08000000
#define IOIIDATA_IOII		0x00000020

#define CMD_RESET		5

static struct ncr_chip zalon720_chip __initdata = {
	.revision_id =	0x0f,
	.burst_max =	3,
	.offset_max =	8,
	.nr_divisor =	4,
	.features =	FE_WIDE | FE_DIFF | FE_EHP| FE_MUX | FE_EA,
};



#if 0
/* FIXME:
 * Is this function dead code? or is someone planning on using it in the
 * future.  The clock = (int) pdc_result[16] does not look correct to
 * me ... I think it should be iodc_data[16].  Since this cause a compile
 * error with the new encapsulated PDC, I'm not compiling in this function.
 * - RB
 */
/* poke SCSI clock out of iodc data */

static u8 iodc_data[32] __attribute__ ((aligned (64)));
static unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0};

static int 
lasi_scsi_clock(void * hpa, int defaultclock)
{
	int clock, status;

	status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 );
	if (status == PDC_RET_OK) {
		clock = (int) pdc_result[16];
	} else {
		printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __func__, status);
		clock = defaultclock; 
	}

	printk(KERN_DEBUG "%s: SCSI clock %d\n", __func__, clock);
 	return clock;
}
#endif

static struct scsi_host_template zalon7xx_template = {
	.module		= THIS_MODULE,
	.proc_name	= "zalon7xx",
};

static int __init
zalon_probe(struct parisc_device *dev)
{
	struct gsc_irq gsc_irq;
	u32 zalon_vers;
	int error = -ENODEV;
	void __iomem *zalon = ioremap(dev->hpa.start, 4096);
	void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET;
	static int unit = 0;
	struct Scsi_Host *host;
	struct ncr_device device;

	__raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND);
	while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY))
		cpu_relax();
	__raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN,
		zalon + IO_MODULE_II_CDATA);

	/* XXX: Save the Zalon version for bug workarounds? */
	zalon_vers = (__raw_readl(zalon + IO_MODULE_II_CDATA) >> 24) & 0x07;

	/* Setup the interrupts first.
	** Later on request_irq() will register the handler.
	*/
	dev->irq = gsc_alloc_irq(&gsc_irq);

	printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __func__,
		zalon_vers, dev->irq);

	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM);

	if (zalon_vers == 0)
		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __func__);

	memset(&device, 0, sizeof(struct ncr_device));

	/* The following three are needed before any other access. */
	__raw_writeb(0x20, io_port + 0x38); /* DCNTL_REG,  EA  */
	__raw_writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */
	__raw_writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */

	/* Initialise ncr_device structure with items required by ncr_attach. */
	device.chip		= zalon720_chip;
	device.host_id		= 7;
	device.dev		= &dev->dev;
	device.slot.base	= dev->hpa.start + GSC_SCSI_ZALON_OFFSET;
	device.slot.base_v	= io_port;
	device.slot.irq		= dev->irq;
	device.differential	= 2;

	host = ncr_attach(&zalon7xx_template, unit, &device);
	if (!host)
		return -ENODEV;

	if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
	  dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ",
		     dev->irq);
		goto fail;
	}

	unit++;

	dev_set_drvdata(&dev->dev, host);

	error = scsi_add_host(host, &dev->dev);
	if (error)
		goto fail_free_irq;

	scsi_scan_host(host);
	return 0;

 fail_free_irq:
	free_irq(dev->irq, host);
 fail:
	ncr53c8xx_release(host);
	return error;
}

static const struct parisc_device_id zalon_tbl[] __initconst = {
	{ HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, 
	{ 0, }
};

MODULE_DEVICE_TABLE(parisc, zalon_tbl);

static void __exit zalon_remove(struct parisc_device *dev)
{
	struct Scsi_Host *host = dev_get_drvdata(&dev->dev);

	scsi_remove_host(host);
	ncr53c8xx_release(host);
	free_irq(dev->irq, host);
}

static struct parisc_driver zalon_driver __refdata = {
	.name =		"zalon",
	.id_table =	zalon_tbl,
	.probe =	zalon_probe,
	.remove =	__exit_p(zalon_remove),
};

static int __init zalon7xx_init(void)
{
	int ret = ncr53c8xx_init();
	if (!ret)
		ret = register_parisc_driver(&zalon_driver);
	if (ret)
		ncr53c8xx_exit();
	return ret;
}

static void __exit zalon7xx_exit(void)
{
	unregister_parisc_driver(&zalon_driver);
	ncr53c8xx_exit();
}

module_init(zalon7xx_init);
module_exit(zalon7xx_exit);