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