2 * Generic Macintosh NCR5380 driver
4 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
6 * derived in part from:
9 * Generic Generic NCR5380 driver
11 * Copyright 1995, Russell King
14 #include <linux/types.h>
15 #include <linux/module.h>
16 #include <linux/ioport.h>
17 #include <linux/init.h>
18 #include <linux/blkdev.h>
19 #include <linux/interrupt.h>
20 #include <linux/platform_device.h>
22 #include <asm/hwtest.h>
24 #include <asm/macints.h>
25 #include <asm/setup.h>
27 #include <scsi/scsi_host.h>
29 /* Definitions for the core NCR5380 driver. */
31 #define NCR5380_implementation_fields unsigned char *pdma_base; \
34 #define NCR5380_read(reg) macscsi_read(instance, reg)
35 #define NCR5380_write(reg, value) macscsi_write(instance, reg, value)
37 #define NCR5380_dma_xfer_len(instance, cmd, phase) \
38 macscsi_dma_xfer_len(instance, cmd)
39 #define NCR5380_dma_recv_setup macscsi_pread
40 #define NCR5380_dma_send_setup macscsi_pwrite
41 #define NCR5380_dma_residual(instance) (hostdata->pdma_residual)
43 #define NCR5380_intr macscsi_intr
44 #define NCR5380_queue_command macscsi_queue_command
45 #define NCR5380_abort macscsi_abort
46 #define NCR5380_bus_reset macscsi_bus_reset
47 #define NCR5380_info macscsi_info
51 static int setup_can_queue
= -1;
52 module_param(setup_can_queue
, int, 0);
53 static int setup_cmd_per_lun
= -1;
54 module_param(setup_cmd_per_lun
, int, 0);
55 static int setup_sg_tablesize
= -1;
56 module_param(setup_sg_tablesize
, int, 0);
57 static int setup_use_pdma
= -1;
58 module_param(setup_use_pdma
, int, 0);
59 static int setup_hostid
= -1;
60 module_param(setup_hostid
, int, 0);
61 static int setup_toshiba_delay
= -1;
62 module_param(setup_toshiba_delay
, int, 0);
65 * NCR 5380 register access functions
68 static inline char macscsi_read(struct Scsi_Host
*instance
, int reg
)
70 return in_8(instance
->base
+ (reg
<< 4));
73 static inline void macscsi_write(struct Scsi_Host
*instance
, int reg
, int value
)
75 out_8(instance
->base
+ (reg
<< 4), value
);
79 static int __init
mac_scsi_setup(char *str
)
83 (void)get_options(str
, ARRAY_SIZE(ints
), ints
);
86 pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
90 setup_can_queue
= ints
[1];
92 setup_cmd_per_lun
= ints
[2];
94 setup_sg_tablesize
= ints
[3];
96 setup_hostid
= ints
[4];
97 /* ints[5] (use_tagged_queuing) is ignored */
99 setup_use_pdma
= ints
[6];
101 setup_toshiba_delay
= ints
[7];
105 __setup("mac5380=", mac_scsi_setup
);
108 /* Pseudo DMA asm originally by Ove Edlund */
110 #define CP_IO_TO_MEM(s,d,n) \
111 __asm__ __volatile__ \
114 " move.w %1,%%d0\n" \
119 " 1: move.b (%0),(%1)+\n" \
120 " 2: dbf %%d0,1b\n" \
121 " move.w %2,%%d0\n" \
124 " 3: move.l (%0),(%1)+\n" \
125 "31: move.l (%0),(%1)+\n" \
126 "32: move.l (%0),(%1)+\n" \
127 "33: move.l (%0),(%1)+\n" \
128 "34: move.l (%0),(%1)+\n" \
129 "35: move.l (%0),(%1)+\n" \
130 "36: move.l (%0),(%1)+\n" \
131 "37: move.l (%0),(%1)+\n" \
132 " 4: dbf %%d0,3b\n" \
133 " move.w %2,%%d0\n" \
137 " 5: move.l (%0),(%1)+\n" \
138 " 6: dbf %%d0,5b\n" \
141 " 7: move.b (%0),(%1)+\n" \
143 " moveq.l #0, %2\n" \
145 ".section .fixup,\"ax\"\n" \
147 "91: moveq.l #1, %2\n" \
149 "94: moveq.l #4, %2\n" \
152 ".section __ex_table,\"a\"\n" \
166 : "=a"(s), "=a"(d), "=d"(n) \
167 : "0"(s), "1"(d), "2"(n) \
170 static int macscsi_pread(struct Scsi_Host
*instance
,
171 unsigned char *dst
, int len
)
173 struct NCR5380_hostdata
*hostdata
= shost_priv(instance
);
174 unsigned char *s
= hostdata
->pdma_base
+ (INPUT_DATA_REG
<< 4);
175 unsigned char *d
= dst
;
179 while (!NCR5380_poll_politely(instance
, BUS_AND_STATUS_REG
,
180 BASR_DRQ
| BASR_PHASE_MATCH
,
181 BASR_DRQ
| BASR_PHASE_MATCH
, HZ
/ 64)) {
182 CP_IO_TO_MEM(s
, d
, n
);
184 transferred
= d
- dst
- n
;
185 hostdata
->pdma_residual
= len
- transferred
;
191 /* Target changed phase early? */
192 if (NCR5380_poll_politely2(instance
, STATUS_REG
, SR_REQ
, SR_REQ
,
193 BUS_AND_STATUS_REG
, BASR_ACK
, BASR_ACK
, HZ
/ 64) < 0)
194 scmd_printk(KERN_ERR
, hostdata
->connected
,
195 "%s: !REQ and !ACK\n", __func__
);
196 if (!(NCR5380_read(BUS_AND_STATUS_REG
) & BASR_PHASE_MATCH
))
199 dsprintk(NDEBUG_PSEUDO_DMA
, instance
,
200 "%s: bus error (%d/%d)\n", __func__
, transferred
, len
);
201 NCR5380_dprint(NDEBUG_PSEUDO_DMA
, instance
);
202 d
= dst
+ transferred
;
203 n
= len
- transferred
;
206 scmd_printk(KERN_ERR
, hostdata
->connected
,
207 "%s: phase mismatch or !DRQ\n", __func__
);
208 NCR5380_dprint(NDEBUG_PSEUDO_DMA
, instance
);
213 #define CP_MEM_TO_IO(s,d,n) \
214 __asm__ __volatile__ \
217 " move.w %0,%%d0\n" \
222 " 1: move.b (%0)+,(%1)\n" \
223 " 2: dbf %%d0,1b\n" \
224 " move.w %2,%%d0\n" \
227 " 3: move.l (%0)+,(%1)\n" \
228 "31: move.l (%0)+,(%1)\n" \
229 "32: move.l (%0)+,(%1)\n" \
230 "33: move.l (%0)+,(%1)\n" \
231 "34: move.l (%0)+,(%1)\n" \
232 "35: move.l (%0)+,(%1)\n" \
233 "36: move.l (%0)+,(%1)\n" \
234 "37: move.l (%0)+,(%1)\n" \
235 " 4: dbf %%d0,3b\n" \
236 " move.w %2,%%d0\n" \
240 " 5: move.l (%0)+,(%1)\n" \
241 " 6: dbf %%d0,5b\n" \
244 " 7: move.b (%0)+,(%1)\n" \
246 " moveq.l #0, %2\n" \
248 ".section .fixup,\"ax\"\n" \
250 "91: moveq.l #1, %2\n" \
252 "94: moveq.l #4, %2\n" \
255 ".section __ex_table,\"a\"\n" \
269 : "=a"(s), "=a"(d), "=d"(n) \
270 : "0"(s), "1"(d), "2"(n) \
273 static int macscsi_pwrite(struct Scsi_Host
*instance
,
274 unsigned char *src
, int len
)
276 struct NCR5380_hostdata
*hostdata
= shost_priv(instance
);
277 unsigned char *s
= src
;
278 unsigned char *d
= hostdata
->pdma_base
+ (OUTPUT_DATA_REG
<< 4);
282 while (!NCR5380_poll_politely(instance
, BUS_AND_STATUS_REG
,
283 BASR_DRQ
| BASR_PHASE_MATCH
,
284 BASR_DRQ
| BASR_PHASE_MATCH
, HZ
/ 64)) {
285 CP_MEM_TO_IO(s
, d
, n
);
287 transferred
= s
- src
- n
;
288 hostdata
->pdma_residual
= len
- transferred
;
290 /* Target changed phase early? */
291 if (NCR5380_poll_politely2(instance
, STATUS_REG
, SR_REQ
, SR_REQ
,
292 BUS_AND_STATUS_REG
, BASR_ACK
, BASR_ACK
, HZ
/ 64) < 0)
293 scmd_printk(KERN_ERR
, hostdata
->connected
,
294 "%s: !REQ and !ACK\n", __func__
);
295 if (!(NCR5380_read(BUS_AND_STATUS_REG
) & BASR_PHASE_MATCH
))
300 if (NCR5380_poll_politely(instance
, TARGET_COMMAND_REG
,
302 TCR_LAST_BYTE_SENT
, HZ
/ 64) < 0)
303 scmd_printk(KERN_ERR
, hostdata
->connected
,
304 "%s: Last Byte Sent timeout\n", __func__
);
308 dsprintk(NDEBUG_PSEUDO_DMA
, instance
,
309 "%s: bus error (%d/%d)\n", __func__
, transferred
, len
);
310 NCR5380_dprint(NDEBUG_PSEUDO_DMA
, instance
);
311 s
= src
+ transferred
;
312 n
= len
- transferred
;
315 scmd_printk(KERN_ERR
, hostdata
->connected
,
316 "%s: phase mismatch or !DRQ\n", __func__
);
317 NCR5380_dprint(NDEBUG_PSEUDO_DMA
, instance
);
322 static int macscsi_dma_xfer_len(struct Scsi_Host
*instance
,
323 struct scsi_cmnd
*cmd
)
325 struct NCR5380_hostdata
*hostdata
= shost_priv(instance
);
327 if (hostdata
->flags
& FLAG_NO_PSEUDO_DMA
||
328 cmd
->SCp
.this_residual
< 16)
331 return cmd
->SCp
.this_residual
;
336 #define DRV_MODULE_NAME "mac_scsi"
337 #define PFX DRV_MODULE_NAME ": "
339 static struct scsi_host_template mac_scsi_template
= {
340 .module
= THIS_MODULE
,
341 .proc_name
= DRV_MODULE_NAME
,
342 .name
= "Macintosh NCR5380 SCSI",
343 .info
= macscsi_info
,
344 .queuecommand
= macscsi_queue_command
,
345 .eh_abort_handler
= macscsi_abort
,
346 .eh_bus_reset_handler
= macscsi_bus_reset
,
351 .use_clustering
= DISABLE_CLUSTERING
,
352 .cmd_size
= NCR5380_CMD_SIZE
,
356 static int __init
mac_scsi_probe(struct platform_device
*pdev
)
358 struct Scsi_Host
*instance
;
361 struct resource
*irq
, *pio_mem
, *pdma_mem
= NULL
;
363 pio_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
367 pdma_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
369 irq
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
371 if (!hwreg_present((unsigned char *)pio_mem
->start
+
372 (STATUS_REG
<< 4))) {
373 pr_info(PFX
"no device detected at %pap\n", &pio_mem
->start
);
377 if (setup_can_queue
> 0)
378 mac_scsi_template
.can_queue
= setup_can_queue
;
379 if (setup_cmd_per_lun
> 0)
380 mac_scsi_template
.cmd_per_lun
= setup_cmd_per_lun
;
381 if (setup_sg_tablesize
>= 0)
382 mac_scsi_template
.sg_tablesize
= setup_sg_tablesize
;
383 if (setup_hostid
>= 0)
384 mac_scsi_template
.this_id
= setup_hostid
& 7;
386 instance
= scsi_host_alloc(&mac_scsi_template
,
387 sizeof(struct NCR5380_hostdata
));
391 instance
->base
= pio_mem
->start
;
393 instance
->irq
= irq
->start
;
395 instance
->irq
= NO_IRQ
;
397 if (pdma_mem
&& setup_use_pdma
) {
398 struct NCR5380_hostdata
*hostdata
= shost_priv(instance
);
400 hostdata
->pdma_base
= (unsigned char *)pdma_mem
->start
;
402 host_flags
|= FLAG_NO_PSEUDO_DMA
;
404 host_flags
|= setup_toshiba_delay
> 0 ? FLAG_TOSHIBA_DELAY
: 0;
406 error
= NCR5380_init(instance
, host_flags
| FLAG_LATE_DMA_SETUP
);
410 if (instance
->irq
!= NO_IRQ
) {
411 error
= request_irq(instance
->irq
, macscsi_intr
, IRQF_SHARED
,
412 "NCR5380", instance
);
417 NCR5380_maybe_reset_bus(instance
);
419 error
= scsi_add_host(instance
, NULL
);
423 platform_set_drvdata(pdev
, instance
);
425 scsi_scan_host(instance
);
429 if (instance
->irq
!= NO_IRQ
)
430 free_irq(instance
->irq
, instance
);
432 NCR5380_exit(instance
);
434 scsi_host_put(instance
);
438 static int __exit
mac_scsi_remove(struct platform_device
*pdev
)
440 struct Scsi_Host
*instance
= platform_get_drvdata(pdev
);
442 scsi_remove_host(instance
);
443 if (instance
->irq
!= NO_IRQ
)
444 free_irq(instance
->irq
, instance
);
445 NCR5380_exit(instance
);
446 scsi_host_put(instance
);
450 static struct platform_driver mac_scsi_driver
= {
451 .remove
= __exit_p(mac_scsi_remove
),
453 .name
= DRV_MODULE_NAME
,
457 module_platform_driver_probe(mac_scsi_driver
, mac_scsi_probe
);
459 MODULE_ALIAS("platform:" DRV_MODULE_NAME
);
460 MODULE_LICENSE("GPL");