0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/ioport.h>
0009 #include <linux/blkdev.h>
0010 #include <linux/init.h>
0011
0012 #include <asm/ecard.h>
0013 #include <asm/io.h>
0014
0015 #include <scsi/scsi_host.h>
0016
0017 #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
0018 #define NCR5380_read(reg) cumanascsi_read(hostdata, reg)
0019 #define NCR5380_write(reg, value) cumanascsi_write(hostdata, reg, value)
0020
0021 #define NCR5380_dma_xfer_len cumanascsi_dma_xfer_len
0022 #define NCR5380_dma_recv_setup cumanascsi_pread
0023 #define NCR5380_dma_send_setup cumanascsi_pwrite
0024 #define NCR5380_dma_residual NCR5380_dma_residual_none
0025
0026 #define NCR5380_intr cumanascsi_intr
0027 #define NCR5380_queue_command cumanascsi_queue_command
0028 #define NCR5380_info cumanascsi_info
0029
0030 #define NCR5380_implementation_fields \
0031 unsigned ctrl
0032
0033 struct NCR5380_hostdata;
0034 static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int);
0035 static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8);
0036
0037 #include "../NCR5380.h"
0038
0039 #define CTRL 0x16fc
0040 #define STAT 0x2004
0041 #define L(v) (((v)<<16)|((v) & 0x0000ffff))
0042 #define H(v) (((v)>>16)|((v) & 0xffff0000))
0043
0044 static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
0045 unsigned char *addr, int len)
0046 {
0047 unsigned long *laddr;
0048 u8 __iomem *base = hostdata->io;
0049 u8 __iomem *dma = hostdata->pdma_io + 0x2000;
0050
0051 if(!len) return 0;
0052
0053 writeb(0x02, base + CTRL);
0054 laddr = (unsigned long *)addr;
0055 while(len >= 32)
0056 {
0057 unsigned int status;
0058 unsigned long v;
0059 status = readb(base + STAT);
0060 if(status & 0x80)
0061 goto end;
0062 if(!(status & 0x40))
0063 continue;
0064 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0065 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0066 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0067 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0068 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0069 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0070 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0071 v=*laddr++; writew(L(v), dma); writew(H(v), dma);
0072 len -= 32;
0073 if(len == 0)
0074 break;
0075 }
0076
0077 addr = (unsigned char *)laddr;
0078 writeb(0x12, base + CTRL);
0079
0080 while(len > 0)
0081 {
0082 unsigned int status;
0083 status = readb(base + STAT);
0084 if(status & 0x80)
0085 goto end;
0086 if(status & 0x40)
0087 {
0088 writeb(*addr++, dma);
0089 if(--len == 0)
0090 break;
0091 }
0092
0093 status = readb(base + STAT);
0094 if(status & 0x80)
0095 goto end;
0096 if(status & 0x40)
0097 {
0098 writeb(*addr++, dma);
0099 if(--len == 0)
0100 break;
0101 }
0102 }
0103 end:
0104 writeb(hostdata->ctrl | 0x40, base + CTRL);
0105
0106 if (len)
0107 return -1;
0108 return 0;
0109 }
0110
0111 static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
0112 unsigned char *addr, int len)
0113 {
0114 unsigned long *laddr;
0115 u8 __iomem *base = hostdata->io;
0116 u8 __iomem *dma = hostdata->pdma_io + 0x2000;
0117
0118 if(!len) return 0;
0119
0120 writeb(0x00, base + CTRL);
0121 laddr = (unsigned long *)addr;
0122 while(len >= 32)
0123 {
0124 unsigned int status;
0125 status = readb(base + STAT);
0126 if(status & 0x80)
0127 goto end;
0128 if(!(status & 0x40))
0129 continue;
0130 *laddr++ = readw(dma) | (readw(dma) << 16);
0131 *laddr++ = readw(dma) | (readw(dma) << 16);
0132 *laddr++ = readw(dma) | (readw(dma) << 16);
0133 *laddr++ = readw(dma) | (readw(dma) << 16);
0134 *laddr++ = readw(dma) | (readw(dma) << 16);
0135 *laddr++ = readw(dma) | (readw(dma) << 16);
0136 *laddr++ = readw(dma) | (readw(dma) << 16);
0137 *laddr++ = readw(dma) | (readw(dma) << 16);
0138 len -= 32;
0139 if(len == 0)
0140 break;
0141 }
0142
0143 addr = (unsigned char *)laddr;
0144 writeb(0x10, base + CTRL);
0145
0146 while(len > 0)
0147 {
0148 unsigned int status;
0149 status = readb(base + STAT);
0150 if(status & 0x80)
0151 goto end;
0152 if(status & 0x40)
0153 {
0154 *addr++ = readb(dma);
0155 if(--len == 0)
0156 break;
0157 }
0158
0159 status = readb(base + STAT);
0160 if(status & 0x80)
0161 goto end;
0162 if(status & 0x40)
0163 {
0164 *addr++ = readb(dma);
0165 if(--len == 0)
0166 break;
0167 }
0168 }
0169 end:
0170 writeb(hostdata->ctrl | 0x40, base + CTRL);
0171
0172 if (len)
0173 return -1;
0174 return 0;
0175 }
0176
0177 static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
0178 struct scsi_cmnd *cmd)
0179 {
0180 return cmd->transfersize;
0181 }
0182
0183 static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
0184 unsigned int reg)
0185 {
0186 u8 __iomem *base = hostdata->io;
0187 u8 val;
0188
0189 writeb(0, base + CTRL);
0190
0191 val = readb(base + 0x2100 + (reg << 2));
0192
0193 hostdata->ctrl = 0x40;
0194 writeb(0x40, base + CTRL);
0195
0196 return val;
0197 }
0198
0199 static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
0200 unsigned int reg, u8 value)
0201 {
0202 u8 __iomem *base = hostdata->io;
0203
0204 writeb(0, base + CTRL);
0205
0206 writeb(value, base + 0x2100 + (reg << 2));
0207
0208 hostdata->ctrl = 0x40;
0209 writeb(0x40, base + CTRL);
0210 }
0211
0212 #include "../NCR5380.c"
0213
0214 static struct scsi_host_template cumanascsi_template = {
0215 .module = THIS_MODULE,
0216 .name = "Cumana 16-bit SCSI",
0217 .info = cumanascsi_info,
0218 .queuecommand = cumanascsi_queue_command,
0219 .eh_abort_handler = NCR5380_abort,
0220 .eh_host_reset_handler = NCR5380_host_reset,
0221 .can_queue = 16,
0222 .this_id = 7,
0223 .sg_tablesize = SG_ALL,
0224 .cmd_per_lun = 2,
0225 .proc_name = "CumanaSCSI-1",
0226 .cmd_size = sizeof(struct NCR5380_cmd),
0227 .max_sectors = 128,
0228 .dma_boundary = PAGE_SIZE - 1,
0229 };
0230
0231 static int cumanascsi1_probe(struct expansion_card *ec,
0232 const struct ecard_id *id)
0233 {
0234 struct Scsi_Host *host;
0235 int ret;
0236
0237 ret = ecard_request_resources(ec);
0238 if (ret)
0239 goto out;
0240
0241 host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
0242 if (!host) {
0243 ret = -ENOMEM;
0244 goto out_release;
0245 }
0246
0247 priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
0248 ecard_resource_len(ec, ECARD_RES_IOCSLOW));
0249 priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
0250 ecard_resource_len(ec, ECARD_RES_MEMC));
0251 if (!priv(host)->io || !priv(host)->pdma_io) {
0252 ret = -ENOMEM;
0253 goto out_unmap;
0254 }
0255
0256 host->irq = ec->irq;
0257
0258 ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
0259 if (ret)
0260 goto out_unmap;
0261
0262 NCR5380_maybe_reset_bus(host);
0263
0264 priv(host)->ctrl = 0;
0265 writeb(0, priv(host)->io + CTRL);
0266
0267 ret = request_irq(host->irq, cumanascsi_intr, 0,
0268 "CumanaSCSI-1", host);
0269 if (ret) {
0270 printk("scsi%d: IRQ%d not free: %d\n",
0271 host->host_no, host->irq, ret);
0272 goto out_exit;
0273 }
0274
0275 ret = scsi_add_host(host, &ec->dev);
0276 if (ret)
0277 goto out_free_irq;
0278
0279 scsi_scan_host(host);
0280 goto out;
0281
0282 out_free_irq:
0283 free_irq(host->irq, host);
0284 out_exit:
0285 NCR5380_exit(host);
0286 out_unmap:
0287 iounmap(priv(host)->io);
0288 iounmap(priv(host)->pdma_io);
0289 scsi_host_put(host);
0290 out_release:
0291 ecard_release_resources(ec);
0292 out:
0293 return ret;
0294 }
0295
0296 static void cumanascsi1_remove(struct expansion_card *ec)
0297 {
0298 struct Scsi_Host *host = ecard_get_drvdata(ec);
0299 void __iomem *base = priv(host)->io;
0300 void __iomem *dma = priv(host)->pdma_io;
0301
0302 ecard_set_drvdata(ec, NULL);
0303
0304 scsi_remove_host(host);
0305 free_irq(host->irq, host);
0306 NCR5380_exit(host);
0307 scsi_host_put(host);
0308 iounmap(base);
0309 iounmap(dma);
0310 ecard_release_resources(ec);
0311 }
0312
0313 static const struct ecard_id cumanascsi1_cids[] = {
0314 { MANU_CUMANA, PROD_CUMANA_SCSI_1 },
0315 { 0xffff, 0xffff }
0316 };
0317
0318 static struct ecard_driver cumanascsi1_driver = {
0319 .probe = cumanascsi1_probe,
0320 .remove = cumanascsi1_remove,
0321 .id_table = cumanascsi1_cids,
0322 .drv = {
0323 .name = "cumanascsi1",
0324 },
0325 };
0326
0327 static int __init cumanascsi_init(void)
0328 {
0329 return ecard_register_driver(&cumanascsi1_driver);
0330 }
0331
0332 static void __exit cumanascsi_exit(void)
0333 {
0334 ecard_remove_driver(&cumanascsi1_driver);
0335 }
0336
0337 module_init(cumanascsi_init);
0338 module_exit(cumanascsi_exit);
0339
0340 MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
0341 MODULE_LICENSE("GPL");