Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Generic Macintosh NCR5380 driver
4 *
5 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
6 *
7 * Copyright 2019 Finn Thain
8 *
9 * derived in part from:
10 */
11/*
12 * Generic Generic NCR5380 driver
13 *
14 * Copyright 1995, Russell King
15 */
16
17#include <linux/delay.h>
18#include <linux/types.h>
19#include <linux/module.h>
20#include <linux/ioport.h>
21#include <linux/init.h>
22#include <linux/blkdev.h>
23#include <linux/interrupt.h>
24#include <linux/platform_device.h>
25
26#include <asm/hwtest.h>
27#include <asm/io.h>
28#include <asm/macintosh.h>
29#include <asm/macints.h>
30#include <asm/setup.h>
31
32#include <scsi/scsi_host.h>
33
34/* Definitions for the core NCR5380 driver. */
35
36#define NCR5380_implementation_fields int pdma_residual
37
38#define NCR5380_read(reg) in_8(hostdata->io + ((reg) << 4))
39#define NCR5380_write(reg, value) out_8(hostdata->io + ((reg) << 4), value)
40
41#define NCR5380_dma_xfer_len macscsi_dma_xfer_len
42#define NCR5380_dma_recv_setup macscsi_pread
43#define NCR5380_dma_send_setup macscsi_pwrite
44#define NCR5380_dma_residual macscsi_dma_residual
45
46#define NCR5380_intr macscsi_intr
47#define NCR5380_queue_command macscsi_queue_command
48#define NCR5380_abort macscsi_abort
49#define NCR5380_host_reset macscsi_host_reset
50#define NCR5380_info macscsi_info
51
52#include "NCR5380.h"
53
54static int setup_can_queue = -1;
55module_param(setup_can_queue, int, 0);
56static int setup_cmd_per_lun = -1;
57module_param(setup_cmd_per_lun, int, 0);
58static int setup_sg_tablesize = -1;
59module_param(setup_sg_tablesize, int, 0);
60static int setup_use_pdma = 512;
61module_param(setup_use_pdma, int, 0);
62static int setup_hostid = -1;
63module_param(setup_hostid, int, 0);
64static int setup_toshiba_delay = -1;
65module_param(setup_toshiba_delay, int, 0);
66
67#ifndef MODULE
68static int __init mac_scsi_setup(char *str)
69{
70 int ints[8];
71
72 (void)get_options(str, ARRAY_SIZE(ints), ints);
73
74 if (ints[0] < 1) {
75 pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
76 return 0;
77 }
78 if (ints[0] >= 1)
79 setup_can_queue = ints[1];
80 if (ints[0] >= 2)
81 setup_cmd_per_lun = ints[2];
82 if (ints[0] >= 3)
83 setup_sg_tablesize = ints[3];
84 if (ints[0] >= 4)
85 setup_hostid = ints[4];
86 /* ints[5] (use_tagged_queuing) is ignored */
87 if (ints[0] >= 6)
88 setup_use_pdma = ints[6];
89 if (ints[0] >= 7)
90 setup_toshiba_delay = ints[7];
91 return 1;
92}
93
94__setup("mac5380=", mac_scsi_setup);
95#endif /* !MODULE */
96
97/*
98 * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
99 * specify the number of bytes between the delays expected from a SCSI target.
100 * This allows the operating system to "prevent bus errors when a target fails
101 * to deliver the next byte within the processor bus error timeout period."
102 * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
103 * so bus errors are unavoidable.
104 *
105 * If a MOVE.B instruction faults, we assume that zero bytes were transferred
106 * and simply retry. That assumption probably depends on target behaviour but
107 * seems to hold up okay. The NOP provides synchronization: without it the
108 * fault can sometimes occur after the program counter has moved past the
109 * offending instruction. Post-increment addressing can't be used.
110 */
111
112#define MOVE_BYTE(operands) \
113 asm volatile ( \
114 "1: moveb " operands " \n" \
115 "11: nop \n" \
116 " addq #1,%0 \n" \
117 " subq #1,%1 \n" \
118 "40: \n" \
119 " \n" \
120 ".section .fixup,\"ax\" \n" \
121 ".even \n" \
122 "90: movel #1, %2 \n" \
123 " jra 40b \n" \
124 ".previous \n" \
125 " \n" \
126 ".section __ex_table,\"a\" \n" \
127 ".align 4 \n" \
128 ".long 1b,90b \n" \
129 ".long 11b,90b \n" \
130 ".previous \n" \
131 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
132
133/*
134 * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
135 * the residual byte count would be uncertain. In that situation the MOVE_WORD
136 * macro clears n in the fixup section to abort the transfer.
137 */
138
139#define MOVE_WORD(operands) \
140 asm volatile ( \
141 "1: movew " operands " \n" \
142 "11: nop \n" \
143 " subq #2,%1 \n" \
144 "40: \n" \
145 " \n" \
146 ".section .fixup,\"ax\" \n" \
147 ".even \n" \
148 "90: movel #0, %1 \n" \
149 " movel #2, %2 \n" \
150 " jra 40b \n" \
151 ".previous \n" \
152 " \n" \
153 ".section __ex_table,\"a\" \n" \
154 ".align 4 \n" \
155 ".long 1b,90b \n" \
156 ".long 11b,90b \n" \
157 ".previous \n" \
158 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
159
160#define MOVE_16_WORDS(operands) \
161 asm volatile ( \
162 "1: movew " operands " \n" \
163 "2: movew " operands " \n" \
164 "3: movew " operands " \n" \
165 "4: movew " operands " \n" \
166 "5: movew " operands " \n" \
167 "6: movew " operands " \n" \
168 "7: movew " operands " \n" \
169 "8: movew " operands " \n" \
170 "9: movew " operands " \n" \
171 "10: movew " operands " \n" \
172 "11: movew " operands " \n" \
173 "12: movew " operands " \n" \
174 "13: movew " operands " \n" \
175 "14: movew " operands " \n" \
176 "15: movew " operands " \n" \
177 "16: movew " operands " \n" \
178 "17: nop \n" \
179 " subl #32,%1 \n" \
180 "40: \n" \
181 " \n" \
182 ".section .fixup,\"ax\" \n" \
183 ".even \n" \
184 "90: movel #0, %1 \n" \
185 " movel #2, %2 \n" \
186 " jra 40b \n" \
187 ".previous \n" \
188 " \n" \
189 ".section __ex_table,\"a\" \n" \
190 ".align 4 \n" \
191 ".long 1b,90b \n" \
192 ".long 2b,90b \n" \
193 ".long 3b,90b \n" \
194 ".long 4b,90b \n" \
195 ".long 5b,90b \n" \
196 ".long 6b,90b \n" \
197 ".long 7b,90b \n" \
198 ".long 8b,90b \n" \
199 ".long 9b,90b \n" \
200 ".long 10b,90b \n" \
201 ".long 11b,90b \n" \
202 ".long 12b,90b \n" \
203 ".long 13b,90b \n" \
204 ".long 14b,90b \n" \
205 ".long 15b,90b \n" \
206 ".long 16b,90b \n" \
207 ".long 17b,90b \n" \
208 ".previous \n" \
209 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
210
211#define MAC_PDMA_DELAY 32
212
213static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
214{
215 unsigned char *addr = start;
216 int result = 0;
217
218 if (n >= 1) {
219 MOVE_BYTE("%3@,%0@");
220 if (result)
221 goto out;
222 }
223 if (n >= 1 && ((unsigned long)addr & 1)) {
224 MOVE_BYTE("%3@,%0@");
225 if (result)
226 goto out;
227 }
228 while (n >= 32)
229 MOVE_16_WORDS("%3@,%0@+");
230 while (n >= 2)
231 MOVE_WORD("%3@,%0@+");
232 if (result)
233 return start - addr; /* Negated to indicate uncertain length */
234 if (n == 1)
235 MOVE_BYTE("%3@,%0@");
236out:
237 return addr - start;
238}
239
240static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
241{
242 unsigned char *addr = start;
243 int result = 0;
244
245 if (n >= 1) {
246 MOVE_BYTE("%0@,%3@");
247 if (result)
248 goto out;
249 }
250 if (n >= 1 && ((unsigned long)addr & 1)) {
251 MOVE_BYTE("%0@,%3@");
252 if (result)
253 goto out;
254 }
255 while (n >= 32)
256 MOVE_16_WORDS("%0@+,%3@");
257 while (n >= 2)
258 MOVE_WORD("%0@+,%3@");
259 if (result)
260 return start - addr; /* Negated to indicate uncertain length */
261 if (n == 1)
262 MOVE_BYTE("%0@,%3@");
263out:
264 return addr - start;
265}
266
267/* The "SCSI DMA" chip on the IIfx implements this register. */
268#define CTRL_REG 0x8
269#define CTRL_INTERRUPTS_ENABLE BIT(1)
270#define CTRL_HANDSHAKE_MODE BIT(3)
271
272static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
273{
274 out_be32(hostdata->io + (CTRL_REG << 4), value);
275}
276
277static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
278 unsigned char *dst, int len)
279{
280 u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
281 unsigned char *d = dst;
282 int result = 0;
283
284 hostdata->pdma_residual = len;
285
286 while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
287 BASR_DRQ | BASR_PHASE_MATCH,
288 BASR_DRQ | BASR_PHASE_MATCH, 0)) {
289 int bytes;
290
291 if (macintosh_config->ident == MAC_MODEL_IIFX)
292 write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
293 CTRL_INTERRUPTS_ENABLE);
294
295 bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
296
297 if (bytes > 0) {
298 d += bytes;
299 hostdata->pdma_residual -= bytes;
300 }
301
302 if (hostdata->pdma_residual == 0)
303 goto out;
304
305 if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
306 BUS_AND_STATUS_REG, BASR_ACK,
307 BASR_ACK, 0) < 0)
308 scmd_printk(KERN_DEBUG, hostdata->connected,
309 "%s: !REQ and !ACK\n", __func__);
310 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
311 goto out;
312
313 if (bytes == 0)
314 udelay(MAC_PDMA_DELAY);
315
316 if (bytes >= 0)
317 continue;
318
319 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
320 "%s: bus error (%d/%d)\n", __func__, d - dst, len);
321 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
322 result = -1;
323 goto out;
324 }
325
326 scmd_printk(KERN_ERR, hostdata->connected,
327 "%s: phase mismatch or !DRQ\n", __func__);
328 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
329 result = -1;
330out:
331 if (macintosh_config->ident == MAC_MODEL_IIFX)
332 write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
333 return result;
334}
335
336static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
337 unsigned char *src, int len)
338{
339 unsigned char *s = src;
340 u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
341 int result = 0;
342
343 hostdata->pdma_residual = len;
344
345 while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
346 BASR_DRQ | BASR_PHASE_MATCH,
347 BASR_DRQ | BASR_PHASE_MATCH, 0)) {
348 int bytes;
349
350 if (macintosh_config->ident == MAC_MODEL_IIFX)
351 write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
352 CTRL_INTERRUPTS_ENABLE);
353
354 bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
355
356 if (bytes > 0) {
357 s += bytes;
358 hostdata->pdma_residual -= bytes;
359 }
360
361 if (hostdata->pdma_residual == 0) {
362 if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
363 TCR_LAST_BYTE_SENT,
364 TCR_LAST_BYTE_SENT,
365 0) < 0) {
366 scmd_printk(KERN_ERR, hostdata->connected,
367 "%s: Last Byte Sent timeout\n", __func__);
368 result = -1;
369 }
370 goto out;
371 }
372
373 if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
374 BUS_AND_STATUS_REG, BASR_ACK,
375 BASR_ACK, 0) < 0)
376 scmd_printk(KERN_DEBUG, hostdata->connected,
377 "%s: !REQ and !ACK\n", __func__);
378 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
379 goto out;
380
381 if (bytes == 0)
382 udelay(MAC_PDMA_DELAY);
383
384 if (bytes >= 0)
385 continue;
386
387 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
388 "%s: bus error (%d/%d)\n", __func__, s - src, len);
389 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
390 result = -1;
391 goto out;
392 }
393
394 scmd_printk(KERN_ERR, hostdata->connected,
395 "%s: phase mismatch or !DRQ\n", __func__);
396 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
397 result = -1;
398out:
399 if (macintosh_config->ident == MAC_MODEL_IIFX)
400 write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
401 return result;
402}
403
404static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
405 struct scsi_cmnd *cmd)
406{
407 int resid = NCR5380_to_ncmd(cmd)->this_residual;
408
409 if (hostdata->flags & FLAG_NO_PSEUDO_DMA || resid < setup_use_pdma)
410 return 0;
411
412 return resid;
413}
414
415static int macscsi_dma_residual(struct NCR5380_hostdata *hostdata)
416{
417 return hostdata->pdma_residual;
418}
419
420#include "NCR5380.c"
421
422#define DRV_MODULE_NAME "mac_scsi"
423#define PFX DRV_MODULE_NAME ": "
424
425static struct scsi_host_template mac_scsi_template = {
426 .module = THIS_MODULE,
427 .proc_name = DRV_MODULE_NAME,
428 .name = "Macintosh NCR5380 SCSI",
429 .info = macscsi_info,
430 .queuecommand = macscsi_queue_command,
431 .eh_abort_handler = macscsi_abort,
432 .eh_host_reset_handler = macscsi_host_reset,
433 .can_queue = 16,
434 .this_id = 7,
435 .sg_tablesize = 1,
436 .cmd_per_lun = 2,
437 .dma_boundary = PAGE_SIZE - 1,
438 .cmd_size = sizeof(struct NCR5380_cmd),
439 .max_sectors = 128,
440};
441
442static int __init mac_scsi_probe(struct platform_device *pdev)
443{
444 struct Scsi_Host *instance;
445 struct NCR5380_hostdata *hostdata;
446 int error;
447 int host_flags = 0;
448 struct resource *irq, *pio_mem, *pdma_mem = NULL;
449
450 pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
451 if (!pio_mem)
452 return -ENODEV;
453
454 pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
455
456 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
457
458 if (!hwreg_present((unsigned char *)pio_mem->start +
459 (STATUS_REG << 4))) {
460 pr_info(PFX "no device detected at %pap\n", &pio_mem->start);
461 return -ENODEV;
462 }
463
464 if (setup_can_queue > 0)
465 mac_scsi_template.can_queue = setup_can_queue;
466 if (setup_cmd_per_lun > 0)
467 mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
468 if (setup_sg_tablesize > 0)
469 mac_scsi_template.sg_tablesize = setup_sg_tablesize;
470 if (setup_hostid >= 0)
471 mac_scsi_template.this_id = setup_hostid & 7;
472
473 instance = scsi_host_alloc(&mac_scsi_template,
474 sizeof(struct NCR5380_hostdata));
475 if (!instance)
476 return -ENOMEM;
477
478 if (irq)
479 instance->irq = irq->start;
480 else
481 instance->irq = NO_IRQ;
482
483 hostdata = shost_priv(instance);
484 hostdata->base = pio_mem->start;
485 hostdata->io = (u8 __iomem *)pio_mem->start;
486
487 if (pdma_mem && setup_use_pdma)
488 hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;
489 else
490 host_flags |= FLAG_NO_PSEUDO_DMA;
491
492 host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
493
494 error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);
495 if (error)
496 goto fail_init;
497
498 if (instance->irq != NO_IRQ) {
499 error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
500 "NCR5380", instance);
501 if (error)
502 goto fail_irq;
503 }
504
505 NCR5380_maybe_reset_bus(instance);
506
507 error = scsi_add_host(instance, NULL);
508 if (error)
509 goto fail_host;
510
511 platform_set_drvdata(pdev, instance);
512
513 scsi_scan_host(instance);
514 return 0;
515
516fail_host:
517 if (instance->irq != NO_IRQ)
518 free_irq(instance->irq, instance);
519fail_irq:
520 NCR5380_exit(instance);
521fail_init:
522 scsi_host_put(instance);
523 return error;
524}
525
526static void __exit mac_scsi_remove(struct platform_device *pdev)
527{
528 struct Scsi_Host *instance = platform_get_drvdata(pdev);
529
530 scsi_remove_host(instance);
531 if (instance->irq != NO_IRQ)
532 free_irq(instance->irq, instance);
533 NCR5380_exit(instance);
534 scsi_host_put(instance);
535}
536
537static struct platform_driver mac_scsi_driver = {
538 .remove_new = __exit_p(mac_scsi_remove),
539 .driver = {
540 .name = DRV_MODULE_NAME,
541 },
542};
543
544module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);
545
546MODULE_ALIAS("platform:" DRV_MODULE_NAME);
547MODULE_LICENSE("GPL");
1/*
2 * Generic Macintosh NCR5380 driver
3 *
4 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
5 *
6 * derived in part from:
7 */
8/*
9 * Generic Generic NCR5380 driver
10 *
11 * Copyright 1995, Russell King
12 *
13 * ALPHA RELEASE 1.
14 *
15 * For more information, please consult
16 *
17 * NCR 5380 Family
18 * SCSI Protocol Controller
19 * Databook
20 *
21 * NCR Microelectronics
22 * 1635 Aeroplaza Drive
23 * Colorado Springs, CO 80916
24 * 1+ (719) 578-3400
25 * 1+ (800) 334-5454
26 */
27
28/*
29 * $Log: mac_NCR5380.c,v $
30 */
31
32#include <linux/types.h>
33#include <linux/stddef.h>
34#include <linux/ctype.h>
35#include <linux/delay.h>
36
37#include <linux/module.h>
38#include <linux/signal.h>
39#include <linux/ioport.h>
40#include <linux/init.h>
41#include <linux/blkdev.h>
42#include <linux/interrupt.h>
43
44#include <asm/io.h>
45#include <asm/irq.h>
46
47#include <asm/macintosh.h>
48#include <asm/macints.h>
49#include <asm/mac_via.h>
50
51#include "scsi.h"
52#include <scsi/scsi_host.h>
53#include "mac_scsi.h"
54
55/* These control the behaviour of the generic 5380 core */
56#define AUTOSENSE
57#define PSEUDO_DMA
58
59#include "NCR5380.h"
60
61#if 0
62#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION)
63#else
64#define NDEBUG (NDEBUG_ABORT)
65#endif
66
67#define RESET_BOOT
68#define DRIVER_SETUP
69
70extern void via_scsi_clear(void);
71
72#ifdef RESET_BOOT
73static void mac_scsi_reset_boot(struct Scsi_Host *instance);
74#endif
75
76static int setup_called = 0;
77static int setup_can_queue = -1;
78static int setup_cmd_per_lun = -1;
79static int setup_sg_tablesize = -1;
80static int setup_use_pdma = -1;
81#ifdef SUPPORT_TAGS
82static int setup_use_tagged_queuing = -1;
83#endif
84static int setup_hostid = -1;
85
86/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
87 * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
88 * need ten times the standard value... */
89#define TOSHIBA_DELAY
90
91#ifdef TOSHIBA_DELAY
92#define AFTER_RESET_DELAY (5*HZ/2)
93#else
94#define AFTER_RESET_DELAY (HZ/2)
95#endif
96
97static volatile unsigned char *mac_scsi_regp = NULL;
98static volatile unsigned char *mac_scsi_drq = NULL;
99static volatile unsigned char *mac_scsi_nodrq = NULL;
100
101
102/*
103 * NCR 5380 register access functions
104 */
105
106#if 0
107/* Debug versions */
108#define CTRL(p,v) (*ctrl = (v))
109
110static char macscsi_read(struct Scsi_Host *instance, int reg)
111{
112 int iobase = instance->io_port;
113 int i;
114 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
115
116 CTRL(iobase, 0);
117 i = in_8(iobase + (reg<<4));
118 CTRL(iobase, 0x40);
119
120 return i;
121}
122
123static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
124{
125 int iobase = instance->io_port;
126 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
127
128 CTRL(iobase, 0);
129 out_8(iobase + (reg<<4), value);
130 CTRL(iobase, 0x40);
131}
132#else
133
134/* Fast versions */
135static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg)
136{
137 return in_8(instance->io_port + (reg<<4));
138}
139
140static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value)
141{
142 out_8(instance->io_port + (reg<<4), value);
143}
144#endif
145
146
147/*
148 * Function : mac_scsi_setup(char *str)
149 *
150 * Purpose : booter command line initialization of the overrides array,
151 *
152 * Inputs : str - comma delimited list of options
153 *
154 */
155
156static int __init mac_scsi_setup(char *str) {
157#ifdef DRIVER_SETUP
158 int ints[7];
159
160 (void)get_options( str, ARRAY_SIZE(ints), ints);
161
162 if (setup_called++ || ints[0] < 1 || ints[0] > 6) {
163 printk(KERN_WARNING "scsi: <mac5380>"
164 " Usage: mac5380=<can_queue>[,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>,<use_pdma>]\n");
165 printk(KERN_ALERT "scsi: <mac5380> Bad Penguin parameters?\n");
166 return 0;
167 }
168
169 if (ints[0] >= 1) {
170 if (ints[1] > 0)
171 /* no limits on this, just > 0 */
172 setup_can_queue = ints[1];
173 }
174 if (ints[0] >= 2) {
175 if (ints[2] > 0)
176 setup_cmd_per_lun = ints[2];
177 }
178 if (ints[0] >= 3) {
179 if (ints[3] >= 0) {
180 setup_sg_tablesize = ints[3];
181 /* Must be <= SG_ALL (255) */
182 if (setup_sg_tablesize > SG_ALL)
183 setup_sg_tablesize = SG_ALL;
184 }
185 }
186 if (ints[0] >= 4) {
187 /* Must be between 0 and 7 */
188 if (ints[4] >= 0 && ints[4] <= 7)
189 setup_hostid = ints[4];
190 else if (ints[4] > 7)
191 printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
192 }
193#ifdef SUPPORT_TAGS
194 if (ints[0] >= 5) {
195 if (ints[5] >= 0)
196 setup_use_tagged_queuing = !!ints[5];
197 }
198
199 if (ints[0] == 6) {
200 if (ints[6] >= 0)
201 setup_use_pdma = ints[6];
202 }
203#else
204 if (ints[0] == 5) {
205 if (ints[5] >= 0)
206 setup_use_pdma = ints[5];
207 }
208#endif /* SUPPORT_TAGS */
209
210#endif /* DRIVER_SETUP */
211 return 1;
212}
213
214__setup("mac5380=", mac_scsi_setup);
215
216/*
217 * Function : int macscsi_detect(struct scsi_host_template * tpnt)
218 *
219 * Purpose : initializes mac NCR5380 driver based on the
220 * command line / compile time port and irq definitions.
221 *
222 * Inputs : tpnt - template for this SCSI adapter.
223 *
224 * Returns : 1 if a host adapter was found, 0 if not.
225 *
226 */
227
228int __init macscsi_detect(struct scsi_host_template * tpnt)
229{
230 static int called = 0;
231 int flags = 0;
232 struct Scsi_Host *instance;
233
234 if (!MACH_IS_MAC || called)
235 return( 0 );
236
237 if (macintosh_config->scsi_type != MAC_SCSI_OLD)
238 return( 0 );
239
240 /* setup variables */
241 tpnt->can_queue =
242 (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
243 tpnt->cmd_per_lun =
244 (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
245 tpnt->sg_tablesize =
246 (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
247
248 if (setup_hostid >= 0)
249 tpnt->this_id = setup_hostid;
250 else {
251 /* use 7 as default */
252 tpnt->this_id = 7;
253 }
254
255#ifdef SUPPORT_TAGS
256 if (setup_use_tagged_queuing < 0)
257 setup_use_tagged_queuing = USE_TAGGED_QUEUING;
258#endif
259
260 /* Once we support multiple 5380s (e.g. DuoDock) we'll do
261 something different here */
262 instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
263 if (instance == NULL)
264 return 0;
265
266 if (macintosh_config->ident == MAC_MODEL_IIFX) {
267 mac_scsi_regp = via1+0x8000;
268 mac_scsi_drq = via1+0xE000;
269 mac_scsi_nodrq = via1+0xC000;
270 /* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */
271 flags = FLAG_NO_PSEUDO_DMA;
272 } else {
273 mac_scsi_regp = via1+0x10000;
274 mac_scsi_drq = via1+0x6000;
275 mac_scsi_nodrq = via1+0x12000;
276 }
277
278 if (! setup_use_pdma)
279 flags = FLAG_NO_PSEUDO_DMA;
280
281 instance->io_port = (unsigned long) mac_scsi_regp;
282 instance->irq = IRQ_MAC_SCSI;
283
284#ifdef RESET_BOOT
285 mac_scsi_reset_boot(instance);
286#endif
287
288 NCR5380_init(instance, flags);
289
290 instance->n_io_port = 255;
291
292 ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
293
294 if (instance->irq != SCSI_IRQ_NONE)
295 if (request_irq(instance->irq, NCR5380_intr, 0, "ncr5380", instance)) {
296 printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
297 instance->host_no, instance->irq);
298 instance->irq = SCSI_IRQ_NONE;
299 }
300
301 printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
302 if (instance->irq == SCSI_IRQ_NONE)
303 printk (KERN_INFO "s disabled");
304 else
305 printk (KERN_INFO " %d", instance->irq);
306 printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
307 instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
308 printk(KERN_INFO "\nscsi%d:", instance->host_no);
309 NCR5380_print_options(instance);
310 printk("\n");
311 called = 1;
312 return 1;
313}
314
315int macscsi_release (struct Scsi_Host *shpnt)
316{
317 if (shpnt->irq != SCSI_IRQ_NONE)
318 free_irq(shpnt->irq, shpnt);
319 NCR5380_exit(shpnt);
320
321 return 0;
322}
323
324#ifdef RESET_BOOT
325/*
326 * Our 'bus reset on boot' function
327 */
328
329static void mac_scsi_reset_boot(struct Scsi_Host *instance)
330{
331 unsigned long end;
332
333 NCR5380_local_declare();
334 NCR5380_setup(instance);
335
336 /*
337 * Do a SCSI reset to clean up the bus during initialization. No messing
338 * with the queues, interrupts, or locks necessary here.
339 */
340
341 printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
342
343 /* get in phase */
344 NCR5380_write( TARGET_COMMAND_REG,
345 PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
346
347 /* assert RST */
348 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
349 /* The min. reset hold time is 25us, so 40us should be enough */
350 udelay( 50 );
351 /* reset RST and interrupt */
352 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
353 NCR5380_read( RESET_PARITY_INTERRUPT_REG );
354
355 for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
356 barrier();
357
358 printk(KERN_INFO " done\n" );
359}
360#endif
361
362const char * macscsi_info (struct Scsi_Host *spnt) {
363 return "";
364}
365
366/*
367 Pseudo-DMA: (Ove Edlund)
368 The code attempts to catch bus errors that occur if one for example
369 "trips over the cable".
370 XXX: Since bus errors in the PDMA routines never happen on my
371 computer, the bus error code is untested.
372 If the code works as intended, a bus error results in Pseudo-DMA
373 beeing disabled, meaning that the driver switches to slow handshake.
374 If bus errors are NOT extremely rare, this has to be changed.
375*/
376
377#define CP_IO_TO_MEM(s,d,len) \
378__asm__ __volatile__ \
379 (" cmp.w #4,%2\n" \
380 " bls 8f\n" \
381 " move.w %1,%%d0\n" \
382 " neg.b %%d0\n" \
383 " and.w #3,%%d0\n" \
384 " sub.w %%d0,%2\n" \
385 " bra 2f\n" \
386 " 1: move.b (%0),(%1)+\n" \
387 " 2: dbf %%d0,1b\n" \
388 " move.w %2,%%d0\n" \
389 " lsr.w #5,%%d0\n" \
390 " bra 4f\n" \
391 " 3: move.l (%0),(%1)+\n" \
392 "31: move.l (%0),(%1)+\n" \
393 "32: move.l (%0),(%1)+\n" \
394 "33: move.l (%0),(%1)+\n" \
395 "34: move.l (%0),(%1)+\n" \
396 "35: move.l (%0),(%1)+\n" \
397 "36: move.l (%0),(%1)+\n" \
398 "37: move.l (%0),(%1)+\n" \
399 " 4: dbf %%d0,3b\n" \
400 " move.w %2,%%d0\n" \
401 " lsr.w #2,%%d0\n" \
402 " and.w #7,%%d0\n" \
403 " bra 6f\n" \
404 " 5: move.l (%0),(%1)+\n" \
405 " 6: dbf %%d0,5b\n" \
406 " and.w #3,%2\n" \
407 " bra 8f\n" \
408 " 7: move.b (%0),(%1)+\n" \
409 " 8: dbf %2,7b\n" \
410 " moveq.l #0, %2\n" \
411 " 9: \n" \
412 ".section .fixup,\"ax\"\n" \
413 " .even\n" \
414 "90: moveq.l #1, %2\n" \
415 " jra 9b\n" \
416 ".previous\n" \
417 ".section __ex_table,\"a\"\n" \
418 " .align 4\n" \
419 " .long 1b,90b\n" \
420 " .long 3b,90b\n" \
421 " .long 31b,90b\n" \
422 " .long 32b,90b\n" \
423 " .long 33b,90b\n" \
424 " .long 34b,90b\n" \
425 " .long 35b,90b\n" \
426 " .long 36b,90b\n" \
427 " .long 37b,90b\n" \
428 " .long 5b,90b\n" \
429 " .long 7b,90b\n" \
430 ".previous" \
431 : "=a"(s), "=a"(d), "=d"(len) \
432 : "0"(s), "1"(d), "2"(len) \
433 : "d0")
434
435
436static int macscsi_pread (struct Scsi_Host *instance,
437 unsigned char *dst, int len)
438{
439 unsigned char *d;
440 volatile unsigned char *s;
441
442 NCR5380_local_declare();
443 NCR5380_setup(instance);
444
445 s = mac_scsi_drq+0x60;
446 d = dst;
447
448/* These conditions are derived from MacOS */
449
450 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)
451 && !(NCR5380_read(STATUS_REG) & SR_REQ))
452 ;
453 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)
454 && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
455 printk(KERN_ERR "Error in macscsi_pread\n");
456 return -1;
457 }
458
459 CP_IO_TO_MEM(s, d, len);
460
461 if (len != 0) {
462 printk(KERN_NOTICE "Bus error in macscsi_pread\n");
463 return -1;
464 }
465
466 return 0;
467}
468
469
470#define CP_MEM_TO_IO(s,d,len) \
471__asm__ __volatile__ \
472 (" cmp.w #4,%2\n" \
473 " bls 8f\n" \
474 " move.w %0,%%d0\n" \
475 " neg.b %%d0\n" \
476 " and.w #3,%%d0\n" \
477 " sub.w %%d0,%2\n" \
478 " bra 2f\n" \
479 " 1: move.b (%0)+,(%1)\n" \
480 " 2: dbf %%d0,1b\n" \
481 " move.w %2,%%d0\n" \
482 " lsr.w #5,%%d0\n" \
483 " bra 4f\n" \
484 " 3: move.l (%0)+,(%1)\n" \
485 "31: move.l (%0)+,(%1)\n" \
486 "32: move.l (%0)+,(%1)\n" \
487 "33: move.l (%0)+,(%1)\n" \
488 "34: move.l (%0)+,(%1)\n" \
489 "35: move.l (%0)+,(%1)\n" \
490 "36: move.l (%0)+,(%1)\n" \
491 "37: move.l (%0)+,(%1)\n" \
492 " 4: dbf %%d0,3b\n" \
493 " move.w %2,%%d0\n" \
494 " lsr.w #2,%%d0\n" \
495 " and.w #7,%%d0\n" \
496 " bra 6f\n" \
497 " 5: move.l (%0)+,(%1)\n" \
498 " 6: dbf %%d0,5b\n" \
499 " and.w #3,%2\n" \
500 " bra 8f\n" \
501 " 7: move.b (%0)+,(%1)\n" \
502 " 8: dbf %2,7b\n" \
503 " moveq.l #0, %2\n" \
504 " 9: \n" \
505 ".section .fixup,\"ax\"\n" \
506 " .even\n" \
507 "90: moveq.l #1, %2\n" \
508 " jra 9b\n" \
509 ".previous\n" \
510 ".section __ex_table,\"a\"\n" \
511 " .align 4\n" \
512 " .long 1b,90b\n" \
513 " .long 3b,90b\n" \
514 " .long 31b,90b\n" \
515 " .long 32b,90b\n" \
516 " .long 33b,90b\n" \
517 " .long 34b,90b\n" \
518 " .long 35b,90b\n" \
519 " .long 36b,90b\n" \
520 " .long 37b,90b\n" \
521 " .long 5b,90b\n" \
522 " .long 7b,90b\n" \
523 ".previous" \
524 : "=a"(s), "=a"(d), "=d"(len) \
525 : "0"(s), "1"(d), "2"(len) \
526 : "d0")
527
528static int macscsi_pwrite (struct Scsi_Host *instance,
529 unsigned char *src, int len)
530{
531 unsigned char *s;
532 volatile unsigned char *d;
533
534 NCR5380_local_declare();
535 NCR5380_setup(instance);
536
537 s = src;
538 d = mac_scsi_drq;
539
540/* These conditions are derived from MacOS */
541
542 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)
543 && (!(NCR5380_read(STATUS_REG) & SR_REQ)
544 || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)))
545 ;
546 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) {
547 printk(KERN_ERR "Error in macscsi_pwrite\n");
548 return -1;
549 }
550
551 CP_MEM_TO_IO(s, d, len);
552
553 if (len != 0) {
554 printk(KERN_NOTICE "Bus error in macscsi_pwrite\n");
555 return -1;
556 }
557
558 return 0;
559}
560
561
562#include "NCR5380.c"
563
564static struct scsi_host_template driver_template = {
565 .proc_name = "Mac5380",
566 .show_info = macscsi_show_info,
567 .write_info = macscsi_write_info,
568 .name = "Macintosh NCR5380 SCSI",
569 .detect = macscsi_detect,
570 .release = macscsi_release,
571 .info = macscsi_info,
572 .queuecommand = macscsi_queue_command,
573 .eh_abort_handler = macscsi_abort,
574 .eh_bus_reset_handler = macscsi_bus_reset,
575 .can_queue = CAN_QUEUE,
576 .this_id = 7,
577 .sg_tablesize = SG_ALL,
578 .cmd_per_lun = CMD_PER_LUN,
579 .use_clustering = DISABLE_CLUSTERING
580};
581
582
583#include "scsi_module.c"