1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds #include <linux/types.h>
31da177e4SLinus Torvalds #include <linux/mm.h>
41da177e4SLinus Torvalds #include <linux/blkdev.h>
51da177e4SLinus Torvalds #include <linux/interrupt.h>
66937d732SChristoph Hellwig #include <linux/init.h>
76937d732SChristoph Hellwig #include <linux/kernel.h>
86937d732SChristoph Hellwig #include <linux/module.h>
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <asm/page.h>
111da177e4SLinus Torvalds #include <asm/mvme147hw.h>
121da177e4SLinus Torvalds #include <asm/irq.h>
131da177e4SLinus Torvalds
1453555fb7SBart Van Assche #include <scsi/scsi.h>
1553555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
1653555fb7SBart Van Assche #include <scsi/scsi_device.h>
1753555fb7SBart Van Assche #include <scsi/scsi_eh.h>
181da177e4SLinus Torvalds #include <scsi/scsi_host.h>
1953555fb7SBart Van Assche #include <scsi/scsi_tcq.h>
201da177e4SLinus Torvalds #include "wd33c93.h"
211da177e4SLinus Torvalds #include "mvme147.h"
221da177e4SLinus Torvalds
mvme147_intr(int irq,void * data)234616ac7eSGeert Uytterhoeven static irqreturn_t mvme147_intr(int irq, void *data)
241da177e4SLinus Torvalds {
254616ac7eSGeert Uytterhoeven struct Scsi_Host *instance = data;
264616ac7eSGeert Uytterhoeven
271da177e4SLinus Torvalds if (irq == MVME147_IRQ_SCSI_PORT)
284616ac7eSGeert Uytterhoeven wd33c93_intr(instance);
291da177e4SLinus Torvalds else
301da177e4SLinus Torvalds m147_pcc->dma_intr = 0x89; /* Ack and enable ints */
311da177e4SLinus Torvalds return IRQ_HANDLED;
321da177e4SLinus Torvalds }
331da177e4SLinus Torvalds
dma_setup(struct scsi_cmnd * cmd,int dir_in)3465396410SHenrik Kretzschmar static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
351da177e4SLinus Torvalds {
36dbb2da55SBart Van Assche struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd);
374616ac7eSGeert Uytterhoeven struct Scsi_Host *instance = cmd->device->host;
384616ac7eSGeert Uytterhoeven struct WD33C93_hostdata *hdata = shost_priv(instance);
391da177e4SLinus Torvalds unsigned char flags = 0x01;
40dbb2da55SBart Van Assche unsigned long addr = virt_to_bus(scsi_pointer->ptr);
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds /* setup dma direction */
431da177e4SLinus Torvalds if (!dir_in)
441da177e4SLinus Torvalds flags |= 0x04;
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds /* remember direction */
47ce195662SGeert Uytterhoeven hdata->dma_dir = dir_in;
481da177e4SLinus Torvalds
49be4540dbSGeert Uytterhoeven if (dir_in) {
501da177e4SLinus Torvalds /* invalidate any cache */
51dbb2da55SBart Van Assche cache_clear(addr, scsi_pointer->this_residual);
52be4540dbSGeert Uytterhoeven } else {
531da177e4SLinus Torvalds /* push any dirty cache */
54dbb2da55SBart Van Assche cache_push(addr, scsi_pointer->this_residual);
55be4540dbSGeert Uytterhoeven }
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds /* start DMA */
58dbb2da55SBart Van Assche m147_pcc->dma_bcr = scsi_pointer->this_residual | (1 << 24);
591da177e4SLinus Torvalds m147_pcc->dma_dadr = addr;
601da177e4SLinus Torvalds m147_pcc->dma_cntrl = flags;
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds /* return success */
631da177e4SLinus Torvalds return 0;
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds
dma_stop(struct Scsi_Host * instance,struct scsi_cmnd * SCpnt,int status)6665396410SHenrik Kretzschmar static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
671da177e4SLinus Torvalds int status)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds m147_pcc->dma_cntrl = 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds
72*c9ac4e73SBart Van Assche static const struct scsi_host_template mvme147_host_template = {
736937d732SChristoph Hellwig .module = THIS_MODULE,
746937d732SChristoph Hellwig .proc_name = "MVME147",
756937d732SChristoph Hellwig .name = "MVME147 built-in SCSI",
766937d732SChristoph Hellwig .queuecommand = wd33c93_queuecommand,
776937d732SChristoph Hellwig .eh_abort_handler = wd33c93_abort,
786937d732SChristoph Hellwig .eh_host_reset_handler = wd33c93_host_reset,
796937d732SChristoph Hellwig .show_info = wd33c93_show_info,
806937d732SChristoph Hellwig .write_info = wd33c93_write_info,
816937d732SChristoph Hellwig .can_queue = CAN_QUEUE,
826937d732SChristoph Hellwig .this_id = 7,
836937d732SChristoph Hellwig .sg_tablesize = SG_ALL,
846937d732SChristoph Hellwig .cmd_per_lun = CMD_PER_LUN,
85dbb2da55SBart Van Assche .cmd_size = sizeof(struct scsi_pointer),
866937d732SChristoph Hellwig };
876937d732SChristoph Hellwig
886937d732SChristoph Hellwig static struct Scsi_Host *mvme147_shost;
896937d732SChristoph Hellwig
mvme147_init(void)906937d732SChristoph Hellwig static int __init mvme147_init(void)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds wd33c93_regs regs;
93ce195662SGeert Uytterhoeven struct WD33C93_hostdata *hdata;
946937d732SChristoph Hellwig int error = -ENOMEM;
951da177e4SLinus Torvalds
966937d732SChristoph Hellwig if (!MACH_IS_MVME147)
971da177e4SLinus Torvalds return 0;
981da177e4SLinus Torvalds
996937d732SChristoph Hellwig mvme147_shost = scsi_host_alloc(&mvme147_host_template,
1006937d732SChristoph Hellwig sizeof(struct WD33C93_hostdata));
1016937d732SChristoph Hellwig if (!mvme147_shost)
1021da177e4SLinus Torvalds goto err_out;
1036937d732SChristoph Hellwig mvme147_shost->base = 0xfffe4000;
1046937d732SChristoph Hellwig mvme147_shost->irq = MVME147_IRQ_SCSI_PORT;
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds regs.SASR = (volatile unsigned char *)0xfffe4000;
1071da177e4SLinus Torvalds regs.SCMD = (volatile unsigned char *)0xfffe4001;
1086937d732SChristoph Hellwig
1096937d732SChristoph Hellwig hdata = shost_priv(mvme147_shost);
110ce195662SGeert Uytterhoeven hdata->no_sync = 0xff;
111ce195662SGeert Uytterhoeven hdata->fast = 0;
112ce195662SGeert Uytterhoeven hdata->dma_mode = CTRL_DMA;
1131da177e4SLinus Torvalds
1146937d732SChristoph Hellwig wd33c93_init(mvme147_shost, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
1156937d732SChristoph Hellwig
1166937d732SChristoph Hellwig error = request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
1176937d732SChristoph Hellwig "MVME147 SCSI PORT", mvme147_shost);
1186937d732SChristoph Hellwig if (error)
1191da177e4SLinus Torvalds goto err_unregister;
1206937d732SChristoph Hellwig error = request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
1216937d732SChristoph Hellwig "MVME147 SCSI DMA", mvme147_shost);
1226937d732SChristoph Hellwig if (error)
1231da177e4SLinus Torvalds goto err_free_irq;
1241da177e4SLinus Torvalds #if 0 /* Disabled; causes problems booting */
1251da177e4SLinus Torvalds m147_pcc->scsi_interrupt = 0x10; /* Assert SCSI bus reset */
1261da177e4SLinus Torvalds udelay(100);
1271da177e4SLinus Torvalds m147_pcc->scsi_interrupt = 0x00; /* Negate SCSI bus reset */
1281da177e4SLinus Torvalds udelay(2000);
1291da177e4SLinus Torvalds m147_pcc->scsi_interrupt = 0x40; /* Clear bus reset interrupt */
1301da177e4SLinus Torvalds #endif
1311da177e4SLinus Torvalds m147_pcc->scsi_interrupt = 0x09; /* Enable interrupt */
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds m147_pcc->dma_cntrl = 0x00; /* ensure DMA is stopped */
1341da177e4SLinus Torvalds m147_pcc->dma_intr = 0x89; /* Ack and enable ints */
1351da177e4SLinus Torvalds
1366937d732SChristoph Hellwig error = scsi_add_host(mvme147_shost, NULL);
1376937d732SChristoph Hellwig if (error)
1386937d732SChristoph Hellwig goto err_free_irq;
1396937d732SChristoph Hellwig scsi_scan_host(mvme147_shost);
1406937d732SChristoph Hellwig return 0;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds err_free_irq:
1436937d732SChristoph Hellwig free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost);
1441da177e4SLinus Torvalds err_unregister:
1456937d732SChristoph Hellwig scsi_host_put(mvme147_shost);
1461da177e4SLinus Torvalds err_out:
1476937d732SChristoph Hellwig return error;
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds
mvme147_exit(void)1506937d732SChristoph Hellwig static void __exit mvme147_exit(void)
1511da177e4SLinus Torvalds {
1526937d732SChristoph Hellwig scsi_remove_host(mvme147_shost);
1536937d732SChristoph Hellwig
1541da177e4SLinus Torvalds /* XXX Make sure DMA is stopped! */
1556937d732SChristoph Hellwig free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost);
1566937d732SChristoph Hellwig free_irq(MVME147_IRQ_SCSI_DMA, mvme147_shost);
1576937d732SChristoph Hellwig
1586937d732SChristoph Hellwig scsi_host_put(mvme147_shost);
1591da177e4SLinus Torvalds }
1606937d732SChristoph Hellwig
1616937d732SChristoph Hellwig module_init(mvme147_init);
1626937d732SChristoph Hellwig module_exit(mvme147_exit);
163