1 // SPDX-License-Identifier: GPL-2.0-only
3 * Oak Generic NCR5380 driver
5 * Copyright 1995-2002, Russell King
8 #include <linux/module.h>
9 #include <linux/ioport.h>
10 #include <linux/blkdev.h>
11 #include <linux/init.h>
13 #include <asm/ecard.h>
16 #include <scsi/scsi_host.h>
18 #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
20 #define NCR5380_read(reg) readb(hostdata->io + ((reg) << 2))
21 #define NCR5380_write(reg, value) writeb(value, hostdata->io + ((reg) << 2))
23 #define NCR5380_dma_xfer_len NCR5380_dma_xfer_none
24 #define NCR5380_dma_recv_setup oakscsi_pread
25 #define NCR5380_dma_send_setup oakscsi_pwrite
26 #define NCR5380_dma_residual NCR5380_dma_residual_none
28 #define NCR5380_queue_command oakscsi_queue_command
29 #define NCR5380_info oakscsi_info
31 #define NCR5380_implementation_fields /* none */
33 #include "../NCR5380.h"
35 #undef START_DMA_INITIATOR_RECEIVE_REG
36 #define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
38 #define STAT ((128 + 16) << 2)
39 #define DATA ((128 + 8) << 2)
41 static inline int oakscsi_pwrite(struct NCR5380_hostdata
*hostdata
,
42 unsigned char *addr
, int len
)
44 u8 __iomem
*base
= hostdata
->io
;
46 printk("writing %p len %d\n",addr
, len
);
51 while (((status
= readw(base
+ STAT
)) & 0x100)==0);
56 static inline int oakscsi_pread(struct NCR5380_hostdata
*hostdata
,
57 unsigned char *addr
, int len
)
59 u8 __iomem
*base
= hostdata
->io
;
61 printk("reading %p len %d\n", addr
, len
);
64 unsigned int status
, timeout
;
69 while (((status
= readw(base
+ STAT
)) & 0x100)==0)
72 if(status
& 0x200 || !timeout
)
74 printk("status = %08X\n", status
);
81 readsw(base
+ DATA
, addr
, 128);
87 b
= (unsigned long) readw(base
+ DATA
);
101 #include "../NCR5380.c"
103 static struct scsi_host_template oakscsi_template
= {
104 .module
= THIS_MODULE
,
105 .name
= "Oak 16-bit SCSI",
106 .info
= oakscsi_info
,
107 .queuecommand
= oakscsi_queue_command
,
108 .eh_abort_handler
= NCR5380_abort
,
109 .eh_host_reset_handler
= NCR5380_host_reset
,
112 .sg_tablesize
= SG_ALL
,
114 .dma_boundary
= PAGE_SIZE
- 1,
115 .proc_name
= "oakscsi",
116 .cmd_size
= NCR5380_CMD_SIZE
,
120 static int oakscsi_probe(struct expansion_card
*ec
, const struct ecard_id
*id
)
122 struct Scsi_Host
*host
;
125 ret
= ecard_request_resources(ec
);
129 host
= scsi_host_alloc(&oakscsi_template
, sizeof(struct NCR5380_hostdata
));
135 priv(host
)->io
= ioremap(ecard_resource_start(ec
, ECARD_RES_MEMC
),
136 ecard_resource_len(ec
, ECARD_RES_MEMC
));
137 if (!priv(host
)->io
) {
144 ret
= NCR5380_init(host
, FLAG_DMA_FIXUP
| FLAG_LATE_DMA_SETUP
);
148 NCR5380_maybe_reset_bus(host
);
150 ret
= scsi_add_host(host
, &ec
->dev
);
154 scsi_scan_host(host
);
160 iounmap(priv(host
)->io
);
164 ecard_release_resources(ec
);
169 static void oakscsi_remove(struct expansion_card
*ec
)
171 struct Scsi_Host
*host
= ecard_get_drvdata(ec
);
172 void __iomem
*base
= priv(host
)->io
;
174 ecard_set_drvdata(ec
, NULL
);
175 scsi_remove_host(host
);
180 ecard_release_resources(ec
);
183 static const struct ecard_id oakscsi_cids
[] = {
184 { MANU_OAK
, PROD_OAK_SCSI
},
188 static struct ecard_driver oakscsi_driver
= {
189 .probe
= oakscsi_probe
,
190 .remove
= oakscsi_remove
,
191 .id_table
= oakscsi_cids
,
197 static int __init
oakscsi_init(void)
199 return ecard_register_driver(&oakscsi_driver
);
202 static void __exit
oakscsi_exit(void)
204 ecard_remove_driver(&oakscsi_driver
);
207 module_init(oakscsi_init
);
208 module_exit(oakscsi_exit
);
210 MODULE_AUTHOR("Russell King");
211 MODULE_DESCRIPTION("Oak SCSI driver");
212 MODULE_LICENSE("GPL");