162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci    dmx3191d.c - driver for the Domex DMX3191D SCSI card.
462306a36Sopenharmony_ci    Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
562306a36Sopenharmony_ci    Portions Copyright (C) 2004 by Christoph Hellwig <hch@lst.de>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci    Based on the generic NCR5380 driver by Drew Eckhardt et al.
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci*/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/ioport.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <asm/io.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <scsi/scsi_host.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * Definitions for the generic 5380 driver.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define NCR5380_read(reg)		inb(hostdata->base + (reg))
2662306a36Sopenharmony_ci#define NCR5380_write(reg, value)	outb(value, hostdata->base + (reg))
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define NCR5380_dma_xfer_len		NCR5380_dma_xfer_none
2962306a36Sopenharmony_ci#define NCR5380_dma_recv_setup		NCR5380_dma_setup_none
3062306a36Sopenharmony_ci#define NCR5380_dma_send_setup		NCR5380_dma_setup_none
3162306a36Sopenharmony_ci#define NCR5380_dma_residual		NCR5380_dma_residual_none
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define NCR5380_implementation_fields	/* none */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "NCR5380.h"
3662306a36Sopenharmony_ci#include "NCR5380.c"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define DMX3191D_DRIVER_NAME	"dmx3191d"
3962306a36Sopenharmony_ci#define DMX3191D_REGION_LEN	8
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const struct scsi_host_template dmx3191d_driver_template = {
4362306a36Sopenharmony_ci	.module			= THIS_MODULE,
4462306a36Sopenharmony_ci	.proc_name		= DMX3191D_DRIVER_NAME,
4562306a36Sopenharmony_ci	.name			= "Domex DMX3191D",
4662306a36Sopenharmony_ci	.info			= NCR5380_info,
4762306a36Sopenharmony_ci	.queuecommand		= NCR5380_queue_command,
4862306a36Sopenharmony_ci	.eh_abort_handler	= NCR5380_abort,
4962306a36Sopenharmony_ci	.eh_host_reset_handler	= NCR5380_host_reset,
5062306a36Sopenharmony_ci	.can_queue		= 32,
5162306a36Sopenharmony_ci	.this_id		= 7,
5262306a36Sopenharmony_ci	.sg_tablesize		= SG_ALL,
5362306a36Sopenharmony_ci	.cmd_per_lun		= 2,
5462306a36Sopenharmony_ci	.dma_boundary		= PAGE_SIZE - 1,
5562306a36Sopenharmony_ci	.cmd_size		= sizeof(struct NCR5380_cmd),
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int dmx3191d_probe_one(struct pci_dev *pdev,
5962306a36Sopenharmony_ci			      const struct pci_device_id *id)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct Scsi_Host *shost;
6262306a36Sopenharmony_ci	struct NCR5380_hostdata *hostdata;
6362306a36Sopenharmony_ci	unsigned long io;
6462306a36Sopenharmony_ci	int error = -ENODEV;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (pci_enable_device(pdev))
6762306a36Sopenharmony_ci		goto out;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	io = pci_resource_start(pdev, 0);
7062306a36Sopenharmony_ci	if (!request_region(io, DMX3191D_REGION_LEN, DMX3191D_DRIVER_NAME)) {
7162306a36Sopenharmony_ci		printk(KERN_ERR "dmx3191: region 0x%lx-0x%lx already reserved\n",
7262306a36Sopenharmony_ci				io, io + DMX3191D_REGION_LEN);
7362306a36Sopenharmony_ci		goto out_disable_device;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	shost = scsi_host_alloc(&dmx3191d_driver_template,
7762306a36Sopenharmony_ci			sizeof(struct NCR5380_hostdata));
7862306a36Sopenharmony_ci	if (!shost)
7962306a36Sopenharmony_ci		goto out_release_region;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	hostdata = shost_priv(shost);
8262306a36Sopenharmony_ci	hostdata->base = io;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* This card does not seem to raise an interrupt on pdev->irq.
8562306a36Sopenharmony_ci	 * Steam-powered SCSI controllers run without an IRQ anyway.
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	shost->irq = NO_IRQ;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	error = NCR5380_init(shost, 0);
9062306a36Sopenharmony_ci	if (error)
9162306a36Sopenharmony_ci		goto out_host_put;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	NCR5380_maybe_reset_bus(shost);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	pci_set_drvdata(pdev, shost);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	error = scsi_add_host(shost, &pdev->dev);
9862306a36Sopenharmony_ci	if (error)
9962306a36Sopenharmony_ci		goto out_exit;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	scsi_scan_host(shost);
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciout_exit:
10562306a36Sopenharmony_ci	NCR5380_exit(shost);
10662306a36Sopenharmony_ciout_host_put:
10762306a36Sopenharmony_ci	scsi_host_put(shost);
10862306a36Sopenharmony_ci out_release_region:
10962306a36Sopenharmony_ci	release_region(io, DMX3191D_REGION_LEN);
11062306a36Sopenharmony_ci out_disable_device:
11162306a36Sopenharmony_ci	pci_disable_device(pdev);
11262306a36Sopenharmony_ci out:
11362306a36Sopenharmony_ci	return error;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void dmx3191d_remove_one(struct pci_dev *pdev)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct Scsi_Host *shost = pci_get_drvdata(pdev);
11962306a36Sopenharmony_ci	struct NCR5380_hostdata *hostdata = shost_priv(shost);
12062306a36Sopenharmony_ci	unsigned long io = hostdata->base;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	scsi_remove_host(shost);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	NCR5380_exit(shost);
12562306a36Sopenharmony_ci	scsi_host_put(shost);
12662306a36Sopenharmony_ci	release_region(io, DMX3191D_REGION_LEN);
12762306a36Sopenharmony_ci	pci_disable_device(pdev);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic struct pci_device_id dmx3191d_pci_tbl[] = {
13162306a36Sopenharmony_ci	{PCI_VENDOR_ID_DOMEX, PCI_DEVICE_ID_DOMEX_DMX3191D,
13262306a36Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
13362306a36Sopenharmony_ci	{ }
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dmx3191d_pci_tbl);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic struct pci_driver dmx3191d_pci_driver = {
13862306a36Sopenharmony_ci	.name		= DMX3191D_DRIVER_NAME,
13962306a36Sopenharmony_ci	.id_table	= dmx3191d_pci_tbl,
14062306a36Sopenharmony_ci	.probe		= dmx3191d_probe_one,
14162306a36Sopenharmony_ci	.remove		= dmx3191d_remove_one,
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cimodule_pci_driver(dmx3191d_pci_driver);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciMODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
14762306a36Sopenharmony_ciMODULE_DESCRIPTION("Domex DMX3191D SCSI driver");
14862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
149