18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8 -*- */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci/* PARISC LASI driver for the 53c700 chip
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
78c2ecf20Sopenharmony_ci**-----------------------------------------------------------------------------
88c2ecf20Sopenharmony_ci**
98c2ecf20Sopenharmony_ci**
108c2ecf20Sopenharmony_ci**-----------------------------------------------------------------------------
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
158c2ecf20Sopenharmony_ci * debugging this driver on the parisc architecture and suggesting
168c2ecf20Sopenharmony_ci * many improvements and bug fixes.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Thanks also go to Linuxcare Inc. for providing several PARISC
198c2ecf20Sopenharmony_ci * machines for me to debug the driver on.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/kernel.h>
238c2ecf20Sopenharmony_ci#include <linux/module.h>
248c2ecf20Sopenharmony_ci#include <linux/init.h>
258c2ecf20Sopenharmony_ci#include <linux/types.h>
268c2ecf20Sopenharmony_ci#include <linux/stat.h>
278c2ecf20Sopenharmony_ci#include <linux/mm.h>
288c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
298c2ecf20Sopenharmony_ci#include <linux/ioport.h>
308c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
318c2ecf20Sopenharmony_ci#include <linux/slab.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <asm/page.h>
348c2ecf20Sopenharmony_ci#include <asm/irq.h>
358c2ecf20Sopenharmony_ci#include <asm/hardware.h>
368c2ecf20Sopenharmony_ci#include <asm/parisc-device.h>
378c2ecf20Sopenharmony_ci#include <asm/delay.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
408c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
418c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h>
428c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_spi.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include "53c700.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciMODULE_AUTHOR("James Bottomley");
478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("lasi700 SCSI Driver");
488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define LASI_700_SVERSION 0x00071
518c2ecf20Sopenharmony_ci#define LASI_710_SVERSION 0x00082
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define LASI700_ID_TABLE {			\
548c2ecf20Sopenharmony_ci	.hw_type	= HPHW_FIO,		\
558c2ecf20Sopenharmony_ci	.sversion	= LASI_700_SVERSION,	\
568c2ecf20Sopenharmony_ci	.hversion	= HVERSION_ANY_ID,	\
578c2ecf20Sopenharmony_ci	.hversion_rev	= HVERSION_REV_ANY_ID,	\
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define LASI710_ID_TABLE {			\
618c2ecf20Sopenharmony_ci	.hw_type	= HPHW_FIO,		\
628c2ecf20Sopenharmony_ci	.sversion	= LASI_710_SVERSION,	\
638c2ecf20Sopenharmony_ci	.hversion	= HVERSION_ANY_ID,	\
648c2ecf20Sopenharmony_ci	.hversion_rev	= HVERSION_REV_ANY_ID,	\
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define LASI700_CLOCK	25
688c2ecf20Sopenharmony_ci#define LASI710_CLOCK	40
698c2ecf20Sopenharmony_ci#define LASI_SCSI_CORE_OFFSET 0x100
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic const struct parisc_device_id lasi700_ids[] __initconst = {
728c2ecf20Sopenharmony_ci	LASI700_ID_TABLE,
738c2ecf20Sopenharmony_ci	LASI710_ID_TABLE,
748c2ecf20Sopenharmony_ci	{ 0 }
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic struct scsi_host_template lasi700_template = {
788c2ecf20Sopenharmony_ci	.name		= "LASI SCSI 53c700",
798c2ecf20Sopenharmony_ci	.proc_name	= "lasi700",
808c2ecf20Sopenharmony_ci	.this_id	= 7,
818c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, lasi700_ids);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int __init
868c2ecf20Sopenharmony_cilasi700_probe(struct parisc_device *dev)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	unsigned long base = dev->hpa.start + LASI_SCSI_CORE_OFFSET;
898c2ecf20Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata;
908c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
938c2ecf20Sopenharmony_ci	if (!hostdata) {
948c2ecf20Sopenharmony_ci		dev_printk(KERN_ERR, &dev->dev, "Failed to allocate host data\n");
958c2ecf20Sopenharmony_ci		return -ENOMEM;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	hostdata->dev = &dev->dev;
998c2ecf20Sopenharmony_ci	dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
1008c2ecf20Sopenharmony_ci	hostdata->base = ioremap(base, 0x100);
1018c2ecf20Sopenharmony_ci	hostdata->differential = 0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (dev->id.sversion == LASI_700_SVERSION) {
1048c2ecf20Sopenharmony_ci		hostdata->clock = LASI700_CLOCK;
1058c2ecf20Sopenharmony_ci		hostdata->force_le_on_be = 1;
1068c2ecf20Sopenharmony_ci	} else {
1078c2ecf20Sopenharmony_ci		hostdata->clock = LASI710_CLOCK;
1088c2ecf20Sopenharmony_ci		hostdata->force_le_on_be = 0;
1098c2ecf20Sopenharmony_ci		hostdata->chip710 = 1;
1108c2ecf20Sopenharmony_ci		hostdata->dmode_extra = DMODE_FC2;
1118c2ecf20Sopenharmony_ci		hostdata->burst_length = 8;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev);
1158c2ecf20Sopenharmony_ci	if (!host)
1168c2ecf20Sopenharmony_ci		goto out_kfree;
1178c2ecf20Sopenharmony_ci	host->this_id = 7;
1188c2ecf20Sopenharmony_ci	host->base = base;
1198c2ecf20Sopenharmony_ci	host->irq = dev->irq;
1208c2ecf20Sopenharmony_ci	if(request_irq(dev->irq, NCR_700_intr, IRQF_SHARED, "lasi700", host)) {
1218c2ecf20Sopenharmony_ci		printk(KERN_ERR "lasi700: request_irq failed!\n");
1228c2ecf20Sopenharmony_ci		goto out_put_host;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	dev_set_drvdata(&dev->dev, host);
1268c2ecf20Sopenharmony_ci	scsi_scan_host(host);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci out_put_host:
1318c2ecf20Sopenharmony_ci	scsi_host_put(host);
1328c2ecf20Sopenharmony_ci out_kfree:
1338c2ecf20Sopenharmony_ci	iounmap(hostdata->base);
1348c2ecf20Sopenharmony_ci	kfree(hostdata);
1358c2ecf20Sopenharmony_ci	return -ENODEV;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int __exit
1398c2ecf20Sopenharmony_cilasi700_driver_remove(struct parisc_device *dev)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct Scsi_Host *host = dev_get_drvdata(&dev->dev);
1428c2ecf20Sopenharmony_ci	struct NCR_700_Host_Parameters *hostdata =
1438c2ecf20Sopenharmony_ci		(struct NCR_700_Host_Parameters *)host->hostdata[0];
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	scsi_remove_host(host);
1468c2ecf20Sopenharmony_ci	NCR_700_release(host);
1478c2ecf20Sopenharmony_ci	free_irq(host->irq, host);
1488c2ecf20Sopenharmony_ci	iounmap(hostdata->base);
1498c2ecf20Sopenharmony_ci	kfree(hostdata);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic struct parisc_driver lasi700_driver __refdata = {
1558c2ecf20Sopenharmony_ci	.name =		"lasi_scsi",
1568c2ecf20Sopenharmony_ci	.id_table =	lasi700_ids,
1578c2ecf20Sopenharmony_ci	.probe =	lasi700_probe,
1588c2ecf20Sopenharmony_ci	.remove =	__exit_p(lasi700_driver_remove),
1598c2ecf20Sopenharmony_ci};
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int __init
1628c2ecf20Sopenharmony_cilasi700_init(void)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return register_parisc_driver(&lasi700_driver);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic void __exit
1688c2ecf20Sopenharmony_cilasi700_exit(void)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	unregister_parisc_driver(&lasi700_driver);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cimodule_init(lasi700_init);
1748c2ecf20Sopenharmony_cimodule_exit(lasi700_exit);
175