1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux. 4 * 5 * Based on work by Alan Hourihane and Kars de Jong 6 * 7 * Rewritten to use 53c700.c by Richard Hirst <richard@sleepie.demon.co.uk> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/blkdev.h> 12 #include <linux/device.h> 13 #include <linux/platform_device.h> 14 #include <linux/init.h> 15 #include <linux/interrupt.h> 16 #include <linux/slab.h> 17 #include <asm/bvme6000hw.h> 18 #include <scsi/scsi_host.h> 19 #include <scsi/scsi_device.h> 20 #include <scsi/scsi_transport.h> 21 #include <scsi/scsi_transport_spi.h> 22 23 #include "53c700.h" 24 25 MODULE_AUTHOR("Richard Hirst <richard@sleepie.demon.co.uk>"); 26 MODULE_DESCRIPTION("BVME6000 NCR53C710 driver"); 27 MODULE_LICENSE("GPL"); 28 29 static struct scsi_host_template bvme6000_scsi_driver_template = { 30 .name = "BVME6000 NCR53c710 SCSI", 31 .proc_name = "BVME6000", 32 .this_id = 7, 33 .module = THIS_MODULE, 34 }; 35 36 static struct platform_device *bvme6000_scsi_device; 37 38 static int 39 bvme6000_probe(struct platform_device *dev) 40 { 41 struct Scsi_Host *host; 42 struct NCR_700_Host_Parameters *hostdata; 43 44 if (!MACH_IS_BVME6000) 45 goto out; 46 47 hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); 48 if (!hostdata) { 49 printk(KERN_ERR "bvme6000-scsi: " 50 "Failed to allocate host data\n"); 51 goto out; 52 } 53 54 /* Fill in the required pieces of hostdata */ 55 hostdata->base = (void __iomem *)BVME_NCR53C710_BASE; 56 hostdata->clock = 40; /* XXX - depends on the CPU clock! */ 57 hostdata->chip710 = 1; 58 hostdata->dmode_extra = DMODE_FC2; 59 hostdata->dcntl_extra = EA_710; 60 hostdata->ctest7_extra = CTEST7_TT1; 61 62 /* and register the chip */ 63 host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, 64 &dev->dev); 65 if (!host) { 66 printk(KERN_ERR "bvme6000-scsi: No host detected; " 67 "board configuration problem?\n"); 68 goto out_free; 69 } 70 host->base = BVME_NCR53C710_BASE; 71 host->this_id = 7; 72 host->irq = BVME_IRQ_SCSI; 73 if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi", 74 host)) { 75 printk(KERN_ERR "bvme6000-scsi: request_irq failed\n"); 76 goto out_put_host; 77 } 78 79 platform_set_drvdata(dev, host); 80 scsi_scan_host(host); 81 82 return 0; 83 84 out_put_host: 85 scsi_host_put(host); 86 out_free: 87 kfree(hostdata); 88 out: 89 return -ENODEV; 90 } 91 92 static int 93 bvme6000_device_remove(struct platform_device *dev) 94 { 95 struct Scsi_Host *host = platform_get_drvdata(dev); 96 struct NCR_700_Host_Parameters *hostdata = shost_priv(host); 97 98 scsi_remove_host(host); 99 NCR_700_release(host); 100 kfree(hostdata); 101 free_irq(host->irq, host); 102 103 return 0; 104 } 105 106 static struct platform_driver bvme6000_scsi_driver = { 107 .driver = { 108 .name = "bvme6000-scsi", 109 }, 110 .probe = bvme6000_probe, 111 .remove = bvme6000_device_remove, 112 }; 113 114 static int __init bvme6000_scsi_init(void) 115 { 116 int err; 117 118 err = platform_driver_register(&bvme6000_scsi_driver); 119 if (err) 120 return err; 121 122 bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi", 123 -1, NULL, 0); 124 if (IS_ERR(bvme6000_scsi_device)) { 125 platform_driver_unregister(&bvme6000_scsi_driver); 126 return PTR_ERR(bvme6000_scsi_device); 127 } 128 129 return 0; 130 } 131 132 static void __exit bvme6000_scsi_exit(void) 133 { 134 platform_device_unregister(bvme6000_scsi_device); 135 platform_driver_unregister(&bvme6000_scsi_driver); 136 } 137 138 module_init(bvme6000_scsi_init); 139 module_exit(bvme6000_scsi_exit); 140