xref: /openbmc/linux/drivers/scsi/mvme147.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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