0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/ioport.h>
0010 #include <linux/blkdev.h>
0011 #include <linux/init.h>
0012
0013 #include <asm/ecard.h>
0014 #include <asm/io.h>
0015
0016 #include <scsi/scsi_host.h>
0017
0018 #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
0019
0020 #define NCR5380_read(reg) readb(hostdata->io + ((reg) << 2))
0021 #define NCR5380_write(reg, value) writeb(value, hostdata->io + ((reg) << 2))
0022
0023 #define NCR5380_dma_xfer_len NCR5380_dma_xfer_none
0024 #define NCR5380_dma_recv_setup oakscsi_pread
0025 #define NCR5380_dma_send_setup oakscsi_pwrite
0026 #define NCR5380_dma_residual NCR5380_dma_residual_none
0027
0028 #define NCR5380_queue_command oakscsi_queue_command
0029 #define NCR5380_info oakscsi_info
0030
0031 #define NCR5380_implementation_fields
0032
0033 #include "../NCR5380.h"
0034
0035 #undef START_DMA_INITIATOR_RECEIVE_REG
0036 #define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
0037
0038 #define STAT ((128 + 16) << 2)
0039 #define DATA ((128 + 8) << 2)
0040
0041 static inline int oakscsi_pwrite(struct NCR5380_hostdata *hostdata,
0042 unsigned char *addr, int len)
0043 {
0044 u8 __iomem *base = hostdata->io;
0045
0046 printk("writing %p len %d\n",addr, len);
0047
0048 while(1)
0049 {
0050 int status;
0051 while (((status = readw(base + STAT)) & 0x100)==0);
0052 }
0053 return 0;
0054 }
0055
0056 static inline int oakscsi_pread(struct NCR5380_hostdata *hostdata,
0057 unsigned char *addr, int len)
0058 {
0059 u8 __iomem *base = hostdata->io;
0060
0061 printk("reading %p len %d\n", addr, len);
0062 while(len > 0)
0063 {
0064 unsigned int status, timeout;
0065 unsigned long b;
0066
0067 timeout = 0x01FFFFFF;
0068
0069 while (((status = readw(base + STAT)) & 0x100)==0)
0070 {
0071 timeout--;
0072 if(status & 0x200 || !timeout)
0073 {
0074 printk("status = %08X\n", status);
0075 return -1;
0076 }
0077 }
0078
0079 if(len >= 128)
0080 {
0081 readsw(base + DATA, addr, 128);
0082 addr += 128;
0083 len -= 128;
0084 }
0085 else
0086 {
0087 b = (unsigned long) readw(base + DATA);
0088 *addr ++ = b;
0089 len -= 1;
0090 if(len)
0091 *addr ++ = b>>8;
0092 len -= 1;
0093 }
0094 }
0095 return 0;
0096 }
0097
0098 #undef STAT
0099 #undef DATA
0100
0101 #include "../NCR5380.c"
0102
0103 static struct scsi_host_template oakscsi_template = {
0104 .module = THIS_MODULE,
0105 .name = "Oak 16-bit SCSI",
0106 .info = oakscsi_info,
0107 .queuecommand = oakscsi_queue_command,
0108 .eh_abort_handler = NCR5380_abort,
0109 .eh_host_reset_handler = NCR5380_host_reset,
0110 .can_queue = 16,
0111 .this_id = 7,
0112 .sg_tablesize = SG_ALL,
0113 .cmd_per_lun = 2,
0114 .dma_boundary = PAGE_SIZE - 1,
0115 .proc_name = "oakscsi",
0116 .cmd_size = sizeof(struct NCR5380_cmd),
0117 .max_sectors = 128,
0118 };
0119
0120 static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
0121 {
0122 struct Scsi_Host *host;
0123 int ret;
0124
0125 ret = ecard_request_resources(ec);
0126 if (ret)
0127 goto out;
0128
0129 host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
0130 if (!host) {
0131 ret = -ENOMEM;
0132 goto release;
0133 }
0134
0135 priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
0136 ecard_resource_len(ec, ECARD_RES_MEMC));
0137 if (!priv(host)->io) {
0138 ret = -ENOMEM;
0139 goto unreg;
0140 }
0141
0142 host->irq = NO_IRQ;
0143
0144 ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
0145 if (ret)
0146 goto out_unmap;
0147
0148 NCR5380_maybe_reset_bus(host);
0149
0150 ret = scsi_add_host(host, &ec->dev);
0151 if (ret)
0152 goto out_exit;
0153
0154 scsi_scan_host(host);
0155 goto out;
0156
0157 out_exit:
0158 NCR5380_exit(host);
0159 out_unmap:
0160 iounmap(priv(host)->io);
0161 unreg:
0162 scsi_host_put(host);
0163 release:
0164 ecard_release_resources(ec);
0165 out:
0166 return ret;
0167 }
0168
0169 static void oakscsi_remove(struct expansion_card *ec)
0170 {
0171 struct Scsi_Host *host = ecard_get_drvdata(ec);
0172 void __iomem *base = priv(host)->io;
0173
0174 ecard_set_drvdata(ec, NULL);
0175 scsi_remove_host(host);
0176
0177 NCR5380_exit(host);
0178 scsi_host_put(host);
0179 iounmap(base);
0180 ecard_release_resources(ec);
0181 }
0182
0183 static const struct ecard_id oakscsi_cids[] = {
0184 { MANU_OAK, PROD_OAK_SCSI },
0185 { 0xffff, 0xffff }
0186 };
0187
0188 static struct ecard_driver oakscsi_driver = {
0189 .probe = oakscsi_probe,
0190 .remove = oakscsi_remove,
0191 .id_table = oakscsi_cids,
0192 .drv = {
0193 .name = "oakscsi",
0194 },
0195 };
0196
0197 static int __init oakscsi_init(void)
0198 {
0199 return ecard_register_driver(&oakscsi_driver);
0200 }
0201
0202 static void __exit oakscsi_exit(void)
0203 {
0204 ecard_remove_driver(&oakscsi_driver);
0205 }
0206
0207 module_init(oakscsi_init);
0208 module_exit(oakscsi_exit);
0209
0210 MODULE_AUTHOR("Russell King");
0211 MODULE_DESCRIPTION("Oak SCSI driver");
0212 MODULE_LICENSE("GPL");
0213