Commit 4d4ffdcf authored by Christoph Hellwig's avatar Christoph Hellwig Committed by James Bottomley

[PATCH] update NCR_D700 for new-style probing

Pretty big patch and untested due to lack of hardware, so handle
it with care :)
parent 7cbecb83
......@@ -92,18 +92,12 @@
#define NCR_D700_VERSION "2.2"
#include <linux/config.h>
#include <linux/blk.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mca.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/byteorder.h>
#include "scsi.h"
#include "hosts.h"
......@@ -111,16 +105,6 @@
#include "53c700.h"
#include "NCR_D700.h"
#ifndef CONFIG_MCA
#error "NCR_D700 driver only compiles for MCA"
#endif
#ifdef NCR_D700_DEBUG
#define STATIC
#else
#define STATIC static
#endif
char *NCR_D700; /* command line from insmod */
MODULE_AUTHOR("James Bottomley");
......@@ -170,34 +154,91 @@ param_setup(char *string)
return 1;
}
#ifndef MODULE
__setup("NCR_D700=", param_setup);
#endif
/* Host template. The 53c700 routine NCR_700_detect will
* fill in all of the missing routines */
static Scsi_Host_Template NCR_D700_driver_template = {
.module = THIS_MODULE,
.name = "NCR Dual 700 MCA",
.proc_name = "NCR_D700",
.this_id = 7,
};
/* private stack allocated structure for passing device information from
* detect to probe */
struct NCR_700_info {
Scsi_Host_Template *tpnt;
int found;
/* We needs this helper because we have two hosts per struct device */
struct NCR_D700_private {
struct device *dev;
struct Scsi_Host *hosts[2];
};
/* Detect a D700 card. Note, because of the set up---the chips are
static int NCR_D700_probe_one(struct NCR_D700_private *p, int chan,
int irq, int slot, u32 region, int differential)
{
struct NCR_700_Host_Parameters *hostdata;
struct Scsi_Host *host;
hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "NCR D700: Failed to allocate host data "
"for channel %d, detatching\n", chan);
return -ENOMEM;
}
memset(hostdata, 0, sizeof(*hostdata));
if (!request_region(region, 64, "NCR_D700")) {
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
region);
kfree(hostdata);
return -ENODEV;
}
/* Fill in the three required pieces of hostdata */
hostdata->base = region;
hostdata->differential = (((1<<chan) & differential) != 0);
hostdata->clock = NCR_D700_CLOCK_MHZ;
/* and register the chip */
host = NCR_700_detect(&NCR_D700_driver_template, hostdata);
if (!host) {
kfree(hostdata);
release_region(host->base, 64);
return -ENOMEM;
}
host->irq = irq;
/* FIXME: Read this from SUS */
host->this_id = id_array[slot * 2 + chan];
printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
chan, host->this_id);
if (request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
printk(KERN_ERR "NCR D700, channel %d: irq problem, "
"detatching\n", chan);
scsi_unregister(host);
NCR_700_release(host);
return -ENODEV;
}
scsi_add_host(host, NULL);
p->hosts[chan] = host;
hostdata->dev = p->dev;
return 0;
}
/* Detect a D700 card. Note, because of the setup --- the chips are
* essentially connectecd to the MCA bus independently, it is easier
* to set them up as two separate host adapters, rather than one
* adapter with two channels */
static int
NCR_D700_probe(struct device *dev)
{
struct NCR_D700_private *p;
int differential;
static int banner = 1;
struct mca_device *mca_dev = to_mca_device(dev);
int slot = mca_dev->slot;
struct NCR_700_info *info = to_mca_driver(dev->driver)->driver_data;
int found = 0;
int irq, i;
int pos3j, pos3k, pos3a, pos3b, pos4;
__u32 base_addr, offset_addr;
struct Scsi_Host *host = NULL;
/* enable board interrupt */
pos4 = mca_device_read_pos(mca_dev, 4);
......@@ -232,8 +273,6 @@ NCR_D700_probe(struct device *dev)
printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr);
info->tpnt->proc_name = "NCR_D700";
/*outb(BOARD_RESET, base_addr);*/
/* clear any pending interrupts */
......@@ -259,70 +298,49 @@ NCR_D700_probe(struct device *dev)
break;
}
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->dev = dev;
/* plumb in both 700 chips */
for(i=0; i<2; i++) {
__u32 region = offset_addr | (0x80 * i);
struct NCR_700_Host_Parameters *hostdata =
kmalloc(sizeof(struct NCR_700_Host_Parameters),
GFP_KERNEL);
if(hostdata == NULL) {
printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i);
continue;
}
memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
if(request_region(region, 64, "NCR_D700") == NULL) {
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region);
kfree(hostdata);
continue;
}
/* Fill in the three required pieces of hostdata */
hostdata->base = region;
hostdata->differential = (((1<<i) & differential) != 0);
hostdata->clock = NCR_D700_CLOCK_MHZ;
/* and register the chip */
if((host = NCR_700_detect(info->tpnt, hostdata)) == NULL) {
kfree(hostdata);
release_region(host->base, 64);
continue;
}
host->irq = irq;
/* FIXME: Read this from SUS */
host->this_id = id_array[slot * 2 + i];
printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
i, host->this_id);
if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
scsi_unregister(host);
NCR_700_release(host);
continue;
}
scsi_set_device(host, dev);
hostdata->dev = dev;
found++;
for (i = 0; i < 2; i++) {
found |= NCR_D700_probe_one(p, i, irq, slot,
offset_addr | (0x80 * i), differential);
}
info->found += found;
if(found) {
mca_device_set_claim(mca_dev, 1);
strncpy(dev->name, "NCR_D700", sizeof(dev->name));
if (!found) {
kfree(p);
return -ENODEV;
}
return found? 0 : -ENODEV;
mca_device_set_claim(mca_dev, 1);
strncpy(dev->name, "NCR_D700", sizeof(dev->name));
dev_set_drvdata(dev, p);
return 0;
}
STATIC int
D700_release(struct Scsi_Host *host)
static void
NCR_D700_remove_one(struct Scsi_Host *host)
{
struct D700_Host_Parameters *hostdata =
(struct D700_Host_Parameters *)host->hostdata[0];
scsi_remove_host(host);
NCR_700_release(host);
kfree(hostdata);
kfree((struct NCR_700_Host_Parameters *)host->hostdata[0]);
free_irq(host->irq, host);
release_region(host->base, 64);
return 1;
}
static int
NCR_D700_remove(struct device *dev)
{
struct NCR_D700_private *p = dev_get_drvdata(dev);
int i;
for (i = 0; i < 2; i++)
NCR_D700_remove_one(p->hosts[i]);
kfree(p);
return 0;
}
static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
......@@ -330,34 +348,29 @@ static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
struct mca_driver NCR_D700_driver = {
.id_table = NCR_D700_id_table,
.driver = {
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
.remove = NCR_D700_remove,
},
};
STATIC int __init
D700_detect(Scsi_Host_Template *tpnt)
static int __init NCR_D700_init(void)
{
struct NCR_700_info info;
if(!MCA_bus)
return 0;
#ifdef MODULE
if(NCR_D700)
if (NCR_D700)
param_setup(NCR_D700);
#endif
info.tpnt = tpnt;
info.found = 0;
NCR_D700_driver.driver_data = &info;
mca_register_driver(&NCR_D700_driver);
return info.found;
return mca_register_driver(&NCR_D700_driver);
}
static Scsi_Host_Template driver_template = NCR_D700_SCSI;
#include "scsi_module.c"
static void __exit NCR_D700_exit(void)
{
mca_unregister_driver(&NCR_D700_driver);
}
module_init(NCR_D700_init);
module_exit(NCR_D700_exit);
__setup("NCR_D700=", param_setup);
......@@ -14,22 +14,6 @@
/* The MCA identifier */
#define NCR_D700_MCA_ID 0x0092
static int D700_detect(Scsi_Host_Template *);
static int D700_release(struct Scsi_Host *host);
/* Host template. Note the name and proc_name are optional, all the
* remaining parameters shown below must be filled in. The 53c700
* routine NCR_700_detect will fill in all of the missing routines */
#define NCR_D700_SCSI { \
.name = "NCR Dual 700 MCA", \
.proc_name = "NCR_D700", \
.detect = D700_detect, \
.release = D700_release, \
.this_id = 7, \
}
/* Defines for the Board registers */
#define BOARD_RESET 0x80 /* board level reset */
#define ADD_PARENB 0x04 /* Address Parity Enabled */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment