Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.uk>
0004  *
0005  *----------------------------------------------------------------------------
0006  *----------------------------------------------------------------------------
0007  *
0008  * MCA card detection code by Trent McNair. (now deleted)
0009  * Fixes to not explicitly nul bss data from Xavier Bestel.
0010  * Some multiboard fixes from Rolf Eike Beer.
0011  * Auto probing of EISA config space from Trevor Hemsley.
0012  *
0013  * Rewritten to use 53c700.c by James.Bottomley@SteelEye.com
0014  */
0015 
0016 #include <linux/module.h>
0017 #include <linux/slab.h>
0018 
0019 #include <linux/blkdev.h>
0020 #include <linux/device.h>
0021 #include <linux/init.h>
0022 #include <linux/eisa.h>
0023 #include <linux/interrupt.h>
0024 #include <scsi/scsi_host.h>
0025 #include <scsi/scsi_device.h>
0026 #include <scsi/scsi_transport.h>
0027 #include <scsi/scsi_transport_spi.h>
0028 
0029 #include "53c700.h"
0030 
0031 
0032 /* Must be enough for EISA */
0033 #define MAX_SLOTS 8
0034 static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
0035 
0036 static char *sim710;        /* command line passed by insmod */
0037 
0038 MODULE_AUTHOR("Richard Hirst");
0039 MODULE_DESCRIPTION("Simple NCR53C710 driver");
0040 MODULE_LICENSE("GPL");
0041 
0042 module_param(sim710, charp, 0);
0043 
0044 #ifdef MODULE
0045 #define ARG_SEP ' '
0046 #else
0047 #define ARG_SEP ','
0048 #endif
0049 
0050 static __init int
0051 param_setup(char *str)
0052 {
0053     char *pos = str, *next;
0054     int slot = -1;
0055 
0056     while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
0057         int val = (int)simple_strtoul(++next, NULL, 0);
0058 
0059         if(!strncmp(pos, "slot:", 5))
0060             slot = val;
0061         else if(!strncmp(pos, "id:", 3)) {
0062             if(slot == -1) {
0063                 printk(KERN_WARNING "sim710: Must specify slot for id parameter\n");
0064             } else if(slot >= MAX_SLOTS) {
0065                 printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val);
0066             } else {
0067                 id_array[slot] = val;
0068             }
0069         }
0070         if((pos = strchr(pos, ARG_SEP)) != NULL)
0071             pos++;
0072     }
0073     return 1;
0074 }
0075 __setup("sim710=", param_setup);
0076 
0077 static struct scsi_host_template sim710_driver_template = {
0078     .name           = "LSI (Symbios) 710 EISA",
0079     .proc_name      = "sim710",
0080     .this_id        = 7,
0081     .module         = THIS_MODULE,
0082 };
0083 
0084 static int sim710_probe_common(struct device *dev, unsigned long base_addr,
0085                    int irq, int clock, int differential,
0086                    int scsi_id)
0087 {
0088     struct Scsi_Host * host = NULL;
0089     struct NCR_700_Host_Parameters *hostdata =
0090         kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
0091 
0092     printk(KERN_NOTICE "sim710: %s\n", dev_name(dev));
0093     printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
0094            irq, clock, base_addr, scsi_id);
0095 
0096     if(hostdata == NULL) {
0097         printk(KERN_ERR "sim710: Failed to allocate host data\n");
0098         goto out;
0099     }
0100 
0101     if(request_region(base_addr, 64, "sim710") == NULL) {
0102         printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
0103                base_addr);
0104         goto out_free;
0105     }
0106 
0107     /* Fill in the three required pieces of hostdata */
0108     hostdata->base = ioport_map(base_addr, 64);
0109     hostdata->differential = differential;
0110     hostdata->clock = clock;
0111     hostdata->chip710 = 1;
0112     hostdata->burst_length = 8;
0113 
0114     /* and register the chip */
0115     if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
0116        == NULL) {
0117         printk(KERN_ERR "sim710: No host detected; card configuration problem?\n");
0118         goto out_release;
0119     }
0120     host->this_id = scsi_id;
0121     host->base = base_addr;
0122     host->irq = irq;
0123     if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) {
0124         printk(KERN_ERR "sim710: request_irq failed\n");
0125         goto out_put_host;
0126     }
0127 
0128     dev_set_drvdata(dev, host);
0129     scsi_scan_host(host);
0130 
0131     return 0;
0132 
0133  out_put_host:
0134     scsi_host_put(host);
0135  out_release:
0136     release_region(base_addr, 64);
0137  out_free:
0138     kfree(hostdata);
0139  out:
0140     return -ENODEV;
0141 }
0142 
0143 static int sim710_device_remove(struct device *dev)
0144 {
0145     struct Scsi_Host *host = dev_get_drvdata(dev);
0146     struct NCR_700_Host_Parameters *hostdata =
0147         (struct NCR_700_Host_Parameters *)host->hostdata[0];
0148 
0149     scsi_remove_host(host);
0150     NCR_700_release(host);
0151     kfree(hostdata);
0152     free_irq(host->irq, host);
0153     release_region(host->base, 64);
0154     return 0;
0155 }
0156 
0157 #ifdef CONFIG_EISA
0158 static struct eisa_device_id sim710_eisa_ids[] = {
0159     { "CPQ4410" },
0160     { "CPQ4411" },
0161     { "HWP0C80" },
0162     { "" }
0163 };
0164 MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
0165 
0166 static int sim710_eisa_probe(struct device *dev)
0167 {
0168     struct eisa_device *edev = to_eisa_device(dev);
0169     unsigned long io_addr = edev->base_addr;
0170     char eisa_cpq_irqs[] = { 11, 14, 15, 10, 9, 0 };
0171     char eisa_hwp_irqs[] = { 3, 4, 5, 7, 12, 10, 11, 0};
0172     char *eisa_irqs;
0173     unsigned char irq_index;
0174     unsigned char irq, differential = 0, scsi_id = 7;
0175 
0176     if(strcmp(edev->id.sig, "HWP0C80") == 0) {
0177         __u8 val;
0178         eisa_irqs =  eisa_hwp_irqs;
0179         irq_index = (inb(io_addr + 0xc85) & 0x7) - 1;
0180 
0181         val = inb(io_addr + 0x4);
0182         scsi_id = ffs(val) - 1;
0183 
0184         if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) {
0185             printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev_name(dev));
0186             scsi_id = 7;
0187         }
0188     } else {
0189         eisa_irqs = eisa_cpq_irqs;
0190         irq_index = inb(io_addr + 0xc88) & 0x07;
0191     }
0192 
0193     if(irq_index >= strlen(eisa_irqs)) {
0194         printk("sim710.c: irq nasty\n");
0195         return -ENODEV;
0196     }
0197 
0198     irq = eisa_irqs[irq_index];
0199         
0200     return sim710_probe_common(dev, io_addr, irq, 50,
0201                    differential, scsi_id);
0202 }
0203 
0204 static struct eisa_driver sim710_eisa_driver = {
0205     .id_table       = sim710_eisa_ids,
0206     .driver = {
0207         .name       = "sim710",
0208         .probe      = sim710_eisa_probe,
0209         .remove     = sim710_device_remove,
0210     },
0211 };
0212 #endif /* CONFIG_EISA */
0213 
0214 static int __init sim710_init(void)
0215 {
0216 #ifdef MODULE
0217     if (sim710)
0218         param_setup(sim710);
0219 #endif
0220 
0221 #ifdef CONFIG_EISA
0222     /*
0223      * FIXME: We'd really like to return -ENODEV if no devices have actually
0224      * been found.  However eisa_driver_register() only reports problems
0225      * with kobject_register() so simply return success for now.
0226      */
0227     eisa_driver_register(&sim710_eisa_driver);
0228 #endif
0229     return 0;
0230 }
0231 
0232 static void __exit sim710_exit(void)
0233 {
0234 #ifdef CONFIG_EISA
0235     eisa_driver_unregister(&sim710_eisa_driver);
0236 #endif
0237 }
0238 
0239 module_init(sim710_init);
0240 module_exit(sim710_exit);