11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Generic Generic NCR5380 driver 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright 1995-2002, Russell King 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds #include <linux/module.h> 71da177e4SLinus Torvalds #include <linux/ioport.h> 81da177e4SLinus Torvalds #include <linux/blkdev.h> 91da177e4SLinus Torvalds #include <linux/init.h> 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include <asm/ecard.h> 121da177e4SLinus Torvalds #include <asm/io.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <scsi/scsi_host.h> 151da177e4SLinus Torvalds 168b801eadSRussell King #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata) 1761e1ce58SFinn Thain #define NCR5380_read(reg) cumanascsi_read(hostdata, reg) 1861e1ce58SFinn Thain #define NCR5380_write(reg, value) cumanascsi_write(hostdata, reg, value) 19ff3d4578SFinn Thain 204a98f896SFinn Thain #define NCR5380_dma_xfer_len cumanascsi_dma_xfer_len 216c4b88caSFinn Thain #define NCR5380_dma_recv_setup cumanascsi_pread 226c4b88caSFinn Thain #define NCR5380_dma_send_setup cumanascsi_pwrite 234a98f896SFinn Thain #define NCR5380_dma_residual NCR5380_dma_residual_none 24ff3d4578SFinn Thain 251da177e4SLinus Torvalds #define NCR5380_intr cumanascsi_intr 261da177e4SLinus Torvalds #define NCR5380_queue_command cumanascsi_queue_command 278c32513bSFinn Thain #define NCR5380_info cumanascsi_info 281da177e4SLinus Torvalds 298b801eadSRussell King #define NCR5380_implementation_fields \ 30820682b1SFinn Thain unsigned ctrl 318b801eadSRussell King 327c606631SFinn Thain struct NCR5380_hostdata; 337c606631SFinn Thain static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int); 347c606631SFinn Thain static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8); 357c606631SFinn Thain 361da177e4SLinus Torvalds #include "../NCR5380.h" 371da177e4SLinus Torvalds 388b801eadSRussell King #define CTRL 0x16fc 398b801eadSRussell King #define STAT 0x2004 401da177e4SLinus Torvalds #define L(v) (((v)<<16)|((v) & 0x0000ffff)) 411da177e4SLinus Torvalds #define H(v) (((v)>>16)|((v) & 0xffff0000)) 421da177e4SLinus Torvalds 434a98f896SFinn Thain static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata, 446c4b88caSFinn Thain unsigned char *addr, int len) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds unsigned long *laddr; 474a98f896SFinn Thain u8 __iomem *base = hostdata->io; 484a98f896SFinn Thain u8 __iomem *dma = hostdata->pdma_io + 0x2000; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds if(!len) return 0; 511da177e4SLinus Torvalds 52820682b1SFinn Thain writeb(0x02, base + CTRL); 531da177e4SLinus Torvalds laddr = (unsigned long *)addr; 541da177e4SLinus Torvalds while(len >= 32) 551da177e4SLinus Torvalds { 568b801eadSRussell King unsigned int status; 571da177e4SLinus Torvalds unsigned long v; 58820682b1SFinn Thain status = readb(base + STAT); 591da177e4SLinus Torvalds if(status & 0x80) 601da177e4SLinus Torvalds goto end; 611da177e4SLinus Torvalds if(!(status & 0x40)) 621da177e4SLinus Torvalds continue; 638b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 648b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 658b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 668b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 678b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 688b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 698b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 708b801eadSRussell King v=*laddr++; writew(L(v), dma); writew(H(v), dma); 711da177e4SLinus Torvalds len -= 32; 721da177e4SLinus Torvalds if(len == 0) 731da177e4SLinus Torvalds break; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds addr = (unsigned char *)laddr; 77820682b1SFinn Thain writeb(0x12, base + CTRL); 788b801eadSRussell King 791da177e4SLinus Torvalds while(len > 0) 801da177e4SLinus Torvalds { 818b801eadSRussell King unsigned int status; 82820682b1SFinn Thain status = readb(base + STAT); 831da177e4SLinus Torvalds if(status & 0x80) 841da177e4SLinus Torvalds goto end; 851da177e4SLinus Torvalds if(status & 0x40) 861da177e4SLinus Torvalds { 878b801eadSRussell King writeb(*addr++, dma); 881da177e4SLinus Torvalds if(--len == 0) 891da177e4SLinus Torvalds break; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 92820682b1SFinn Thain status = readb(base + STAT); 931da177e4SLinus Torvalds if(status & 0x80) 941da177e4SLinus Torvalds goto end; 951da177e4SLinus Torvalds if(status & 0x40) 961da177e4SLinus Torvalds { 978b801eadSRussell King writeb(*addr++, dma); 981da177e4SLinus Torvalds if(--len == 0) 991da177e4SLinus Torvalds break; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds end: 1034a98f896SFinn Thain writeb(hostdata->ctrl | 0x40, base + CTRL); 104438af51cSFinn Thain 105438af51cSFinn Thain if (len) 106438af51cSFinn Thain return -1; 107438af51cSFinn Thain return 0; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1104a98f896SFinn Thain static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata, 1116c4b88caSFinn Thain unsigned char *addr, int len) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds unsigned long *laddr; 1144a98f896SFinn Thain u8 __iomem *base = hostdata->io; 1154a98f896SFinn Thain u8 __iomem *dma = hostdata->pdma_io + 0x2000; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds if(!len) return 0; 1181da177e4SLinus Torvalds 119820682b1SFinn Thain writeb(0x00, base + CTRL); 1201da177e4SLinus Torvalds laddr = (unsigned long *)addr; 1211da177e4SLinus Torvalds while(len >= 32) 1221da177e4SLinus Torvalds { 1238b801eadSRussell King unsigned int status; 124820682b1SFinn Thain status = readb(base + STAT); 1251da177e4SLinus Torvalds if(status & 0x80) 1261da177e4SLinus Torvalds goto end; 1271da177e4SLinus Torvalds if(!(status & 0x40)) 1281da177e4SLinus Torvalds continue; 1298b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1308b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1318b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1328b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1338b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1348b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1358b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1368b801eadSRussell King *laddr++ = readw(dma) | (readw(dma) << 16); 1371da177e4SLinus Torvalds len -= 32; 1381da177e4SLinus Torvalds if(len == 0) 1391da177e4SLinus Torvalds break; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds addr = (unsigned char *)laddr; 143820682b1SFinn Thain writeb(0x10, base + CTRL); 1448b801eadSRussell King 1451da177e4SLinus Torvalds while(len > 0) 1461da177e4SLinus Torvalds { 1478b801eadSRussell King unsigned int status; 148820682b1SFinn Thain status = readb(base + STAT); 1491da177e4SLinus Torvalds if(status & 0x80) 1501da177e4SLinus Torvalds goto end; 1511da177e4SLinus Torvalds if(status & 0x40) 1521da177e4SLinus Torvalds { 1538b801eadSRussell King *addr++ = readb(dma); 1541da177e4SLinus Torvalds if(--len == 0) 1551da177e4SLinus Torvalds break; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 158820682b1SFinn Thain status = readb(base + STAT); 1591da177e4SLinus Torvalds if(status & 0x80) 1601da177e4SLinus Torvalds goto end; 1611da177e4SLinus Torvalds if(status & 0x40) 1621da177e4SLinus Torvalds { 1638b801eadSRussell King *addr++ = readb(dma); 1641da177e4SLinus Torvalds if(--len == 0) 1651da177e4SLinus Torvalds break; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds end: 1694a98f896SFinn Thain writeb(hostdata->ctrl | 0x40, base + CTRL); 170438af51cSFinn Thain 171438af51cSFinn Thain if (len) 172438af51cSFinn Thain return -1; 173438af51cSFinn Thain return 0; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1764a98f896SFinn Thain static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, 1774a98f896SFinn Thain struct scsi_cmnd *cmd) 1784a98f896SFinn Thain { 1794a98f896SFinn Thain return cmd->transfersize; 1804a98f896SFinn Thain } 1814a98f896SFinn Thain 18261e1ce58SFinn Thain static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata, 18361e1ce58SFinn Thain unsigned int reg) 1841da177e4SLinus Torvalds { 18561e1ce58SFinn Thain u8 __iomem *base = hostdata->io; 18661e1ce58SFinn Thain u8 val; 1871da177e4SLinus Torvalds 1888b801eadSRussell King writeb(0, base + CTRL); 1891da177e4SLinus Torvalds 1908b801eadSRussell King val = readb(base + 0x2100 + (reg << 2)); 1918b801eadSRussell King 19261e1ce58SFinn Thain hostdata->ctrl = 0x40; 1938b801eadSRussell King writeb(0x40, base + CTRL); 1948b801eadSRussell King 1958b801eadSRussell King return val; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 19861e1ce58SFinn Thain static void cumanascsi_write(struct NCR5380_hostdata *hostdata, 19961e1ce58SFinn Thain unsigned int reg, u8 value) 2001da177e4SLinus Torvalds { 20161e1ce58SFinn Thain u8 __iomem *base = hostdata->io; 2021da177e4SLinus Torvalds 2038b801eadSRussell King writeb(0, base + CTRL); 2048b801eadSRussell King 2058b801eadSRussell King writeb(value, base + 0x2100 + (reg << 2)); 2068b801eadSRussell King 20761e1ce58SFinn Thain hostdata->ctrl = 0x40; 2088b801eadSRussell King writeb(0x40, base + CTRL); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds #include "../NCR5380.c" 2121da177e4SLinus Torvalds 213d0be4a7dSChristoph Hellwig static struct scsi_host_template cumanascsi_template = { 2141da177e4SLinus Torvalds .module = THIS_MODULE, 2151da177e4SLinus Torvalds .name = "Cumana 16-bit SCSI", 2161da177e4SLinus Torvalds .info = cumanascsi_info, 2171da177e4SLinus Torvalds .queuecommand = cumanascsi_queue_command, 2181da177e4SLinus Torvalds .eh_abort_handler = NCR5380_abort, 21912e5fc66SHannes Reinecke .eh_host_reset_handler = NCR5380_host_reset, 2201da177e4SLinus Torvalds .can_queue = 16, 2211da177e4SLinus Torvalds .this_id = 7, 2221da177e4SLinus Torvalds .sg_tablesize = SG_ALL, 2231da177e4SLinus Torvalds .cmd_per_lun = 2, 2241da177e4SLinus Torvalds .use_clustering = DISABLE_CLUSTERING, 2251da177e4SLinus Torvalds .proc_name = "CumanaSCSI-1", 22632b26a10SFinn Thain .cmd_size = NCR5380_CMD_SIZE, 2270a4e3612SFinn Thain .max_sectors = 128, 2281da177e4SLinus Torvalds }; 2291da177e4SLinus Torvalds 2306f039790SGreg Kroah-Hartman static int cumanascsi1_probe(struct expansion_card *ec, 2316f039790SGreg Kroah-Hartman const struct ecard_id *id) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds struct Scsi_Host *host; 2348b801eadSRussell King int ret; 2351da177e4SLinus Torvalds 2368b801eadSRussell King ret = ecard_request_resources(ec); 2378b801eadSRussell King if (ret) 2381da177e4SLinus Torvalds goto out; 2391da177e4SLinus Torvalds 2408b801eadSRussell King host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); 2418b801eadSRussell King if (!host) { 2428b801eadSRussell King ret = -ENOMEM; 2438b801eadSRussell King goto out_release; 2448b801eadSRussell King } 2458b801eadSRussell King 246820682b1SFinn Thain priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW), 2478b801eadSRussell King ecard_resource_len(ec, ECARD_RES_IOCSLOW)); 248820682b1SFinn Thain priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), 2498b801eadSRussell King ecard_resource_len(ec, ECARD_RES_MEMC)); 250820682b1SFinn Thain if (!priv(host)->io || !priv(host)->pdma_io) { 2518b801eadSRussell King ret = -ENOMEM; 2528b801eadSRussell King goto out_unmap; 2538b801eadSRussell King } 2548b801eadSRussell King 2551da177e4SLinus Torvalds host->irq = ec->irq; 2561da177e4SLinus Torvalds 2578053b0eeSFinn Thain ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP); 2580ad0eff9SFinn Thain if (ret) 2590ad0eff9SFinn Thain goto out_unmap; 2601da177e4SLinus Torvalds 261b6488f97SFinn Thain NCR5380_maybe_reset_bus(host); 262b6488f97SFinn Thain 2638b801eadSRussell King priv(host)->ctrl = 0; 264820682b1SFinn Thain writeb(0, priv(host)->io + CTRL); 2658b801eadSRussell King 2664909cc2bSMichael Opdenacker ret = request_irq(host->irq, cumanascsi_intr, 0, 2671da177e4SLinus Torvalds "CumanaSCSI-1", host); 2681da177e4SLinus Torvalds if (ret) { 2691da177e4SLinus Torvalds printk("scsi%d: IRQ%d not free: %d\n", 2701da177e4SLinus Torvalds host->host_no, host->irq, ret); 2710ad0eff9SFinn Thain goto out_exit; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds ret = scsi_add_host(host, &ec->dev); 2751da177e4SLinus Torvalds if (ret) 2761da177e4SLinus Torvalds goto out_free_irq; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds scsi_scan_host(host); 2791da177e4SLinus Torvalds goto out; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds out_free_irq: 2821da177e4SLinus Torvalds free_irq(host->irq, host); 2830ad0eff9SFinn Thain out_exit: 2840ad0eff9SFinn Thain NCR5380_exit(host); 2858b801eadSRussell King out_unmap: 286820682b1SFinn Thain iounmap(priv(host)->io); 287820682b1SFinn Thain iounmap(priv(host)->pdma_io); 2881da177e4SLinus Torvalds scsi_host_put(host); 2898b801eadSRussell King out_release: 2908b801eadSRussell King ecard_release_resources(ec); 2911da177e4SLinus Torvalds out: 2921da177e4SLinus Torvalds return ret; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2956f039790SGreg Kroah-Hartman static void cumanascsi1_remove(struct expansion_card *ec) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds struct Scsi_Host *host = ecard_get_drvdata(ec); 298820682b1SFinn Thain void __iomem *base = priv(host)->io; 299820682b1SFinn Thain void __iomem *dma = priv(host)->pdma_io; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds ecard_set_drvdata(ec, NULL); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds scsi_remove_host(host); 3041da177e4SLinus Torvalds free_irq(host->irq, host); 3051da177e4SLinus Torvalds NCR5380_exit(host); 3061da177e4SLinus Torvalds scsi_host_put(host); 307820682b1SFinn Thain iounmap(base); 308820682b1SFinn Thain iounmap(dma); 3098b801eadSRussell King ecard_release_resources(ec); 3101da177e4SLinus Torvalds } 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds static const struct ecard_id cumanascsi1_cids[] = { 3131da177e4SLinus Torvalds { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, 3141da177e4SLinus Torvalds { 0xffff, 0xffff } 3151da177e4SLinus Torvalds }; 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds static struct ecard_driver cumanascsi1_driver = { 3181da177e4SLinus Torvalds .probe = cumanascsi1_probe, 3196f039790SGreg Kroah-Hartman .remove = cumanascsi1_remove, 3201da177e4SLinus Torvalds .id_table = cumanascsi1_cids, 3211da177e4SLinus Torvalds .drv = { 3221da177e4SLinus Torvalds .name = "cumanascsi1", 3231da177e4SLinus Torvalds }, 3241da177e4SLinus Torvalds }; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds static int __init cumanascsi_init(void) 3271da177e4SLinus Torvalds { 3281da177e4SLinus Torvalds return ecard_register_driver(&cumanascsi1_driver); 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds static void __exit cumanascsi_exit(void) 3321da177e4SLinus Torvalds { 3331da177e4SLinus Torvalds ecard_remove_driver(&cumanascsi1_driver); 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds module_init(cumanascsi_init); 3371da177e4SLinus Torvalds module_exit(cumanascsi_exit); 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines"); 3401da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 341