18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on work by Alan Hourihane and Kars de Jong
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Rewritten to use 53c700.c by Richard Hirst <richard@sleepie.demon.co.uk>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <asm/bvme6000hw.h>
188c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
198c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
208c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h>
218c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_spi.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "53c700.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Hirst <richard@sleepie.demon.co.uk>");
268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BVME6000 NCR53C710 driver");
278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic struct scsi_host_template bvme6000_scsi_driver_template = {
308c2ecf20Sopenharmony_ci	.name			= "BVME6000 NCR53c710 SCSI",
318c2ecf20Sopenharmony_ci	.proc_name		= "BVME6000",
328c2ecf20Sopenharmony_ci	.this_id		= 7,
338c2ecf20Sopenharmony_ci	.module			= THIS_MODULE,
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic struct platform_device *bvme6000_scsi_device;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int
398c2ecf20Sopenharmony_cibvme6000_probe(struct platform_device *dev)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
428c2ecf20Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (!MACH_IS_BVME6000)
458c2ecf20Sopenharmony_ci		goto out;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
488c2ecf20Sopenharmony_ci	if (!hostdata) {
498c2ecf20Sopenharmony_ci		printk(KERN_ERR "bvme6000-scsi: "
508c2ecf20Sopenharmony_ci				"Failed to allocate host data\n");
518c2ecf20Sopenharmony_ci		goto out;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* Fill in the required pieces of hostdata */
558c2ecf20Sopenharmony_ci	hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
568c2ecf20Sopenharmony_ci	hostdata->clock = 40;	/* XXX - depends on the CPU clock! */
578c2ecf20Sopenharmony_ci	hostdata->chip710 = 1;
588c2ecf20Sopenharmony_ci	hostdata->dmode_extra = DMODE_FC2;
598c2ecf20Sopenharmony_ci	hostdata->dcntl_extra = EA_710;
608c2ecf20Sopenharmony_ci	hostdata->ctest7_extra = CTEST7_TT1;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* and register the chip */
638c2ecf20Sopenharmony_ci	host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata,
648c2ecf20Sopenharmony_ci			      &dev->dev);
658c2ecf20Sopenharmony_ci	if (!host) {
668c2ecf20Sopenharmony_ci		printk(KERN_ERR "bvme6000-scsi: No host detected; "
678c2ecf20Sopenharmony_ci				"board configuration problem?\n");
688c2ecf20Sopenharmony_ci		goto out_free;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci	host->base = BVME_NCR53C710_BASE;
718c2ecf20Sopenharmony_ci	host->this_id = 7;
728c2ecf20Sopenharmony_ci	host->irq = BVME_IRQ_SCSI;
738c2ecf20Sopenharmony_ci	if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi",
748c2ecf20Sopenharmony_ci			host)) {
758c2ecf20Sopenharmony_ci		printk(KERN_ERR "bvme6000-scsi: request_irq failed\n");
768c2ecf20Sopenharmony_ci		goto out_put_host;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	platform_set_drvdata(dev, host);
808c2ecf20Sopenharmony_ci	scsi_scan_host(host);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci out_put_host:
858c2ecf20Sopenharmony_ci	scsi_host_put(host);
868c2ecf20Sopenharmony_ci out_free:
878c2ecf20Sopenharmony_ci	kfree(hostdata);
888c2ecf20Sopenharmony_ci out:
898c2ecf20Sopenharmony_ci	return -ENODEV;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int
938c2ecf20Sopenharmony_cibvme6000_device_remove(struct platform_device *dev)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct Scsi_Host *host = platform_get_drvdata(dev);
968c2ecf20Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	scsi_remove_host(host);
998c2ecf20Sopenharmony_ci	NCR_700_release(host);
1008c2ecf20Sopenharmony_ci	kfree(hostdata);
1018c2ecf20Sopenharmony_ci	free_irq(host->irq, host);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic struct platform_driver bvme6000_scsi_driver = {
1078c2ecf20Sopenharmony_ci	.driver = {
1088c2ecf20Sopenharmony_ci		.name		= "bvme6000-scsi",
1098c2ecf20Sopenharmony_ci	},
1108c2ecf20Sopenharmony_ci	.probe		= bvme6000_probe,
1118c2ecf20Sopenharmony_ci	.remove		= bvme6000_device_remove,
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic int __init bvme6000_scsi_init(void)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	int err;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	err = platform_driver_register(&bvme6000_scsi_driver);
1198c2ecf20Sopenharmony_ci	if (err)
1208c2ecf20Sopenharmony_ci		return err;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi",
1238c2ecf20Sopenharmony_ci							       -1, NULL, 0);
1248c2ecf20Sopenharmony_ci	if (IS_ERR(bvme6000_scsi_device)) {
1258c2ecf20Sopenharmony_ci		platform_driver_unregister(&bvme6000_scsi_driver);
1268c2ecf20Sopenharmony_ci		return PTR_ERR(bvme6000_scsi_device);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic void __exit bvme6000_scsi_exit(void)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	platform_device_unregister(bvme6000_scsi_device);
1358c2ecf20Sopenharmony_ci	platform_driver_unregister(&bvme6000_scsi_driver);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cimodule_init(bvme6000_scsi_init);
1398c2ecf20Sopenharmony_cimodule_exit(bvme6000_scsi_exit);
140