Commit 411aa554 authored by David S. Miller's avatar David S. Miller

[SCSI] sparc: Port esp to new SBUS driver layer.

This also turns the driver into a new-style scsi driver.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 69b5c4f1
/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
/* esp.c: ESP Sun SCSI driver.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/
/* TODO:
......@@ -185,11 +184,6 @@ enum {
/*5*/ do_intr_end
};
/* The master ring of all esp hosts we are managing in this driver. */
static struct esp *espchain;
static DEFINE_SPINLOCK(espchain_lock);
static int esps_running = 0;
/* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
......@@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT);
}
static void esp_chain_add(struct esp *esp)
{
spin_lock_irq(&espchain_lock);
if (espchain) {
struct esp *elink = espchain;
while (elink->next)
elink = elink->next;
elink->next = esp;
} else {
espchain = esp;
}
esp->next = NULL;
spin_unlock_irq(&espchain_lock);
}
static void esp_chain_del(struct esp *esp)
{
spin_lock_irq(&espchain_lock);
if (espchain == esp) {
espchain = esp->next;
} else {
struct esp *elink = espchain;
while (elink->next != esp)
elink = elink->next;
elink->next = esp->next;
}
esp->next = NULL;
spin_unlock_irq(&espchain_lock);
}
static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{
struct sbus_dev *sdev = esp->sdev;
......@@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp)
{
struct sbus_dev *sdev = esp->sdev;
struct device_node *dp = sdev->ofdev.node;
esp->scsi_id = prom_getintdefault(esp->prom_node,
"initiator-id",
-1);
esp->scsi_id = of_getintprop_default(dp,
"initiator-id",
-1);
if (esp->scsi_id == -1)
esp->scsi_id = prom_getintdefault(esp->prom_node,
"scsi-initiator-id",
-1);
esp->scsi_id = of_getintprop_default(dp,
"scsi-initiator-id",
-1);
if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 :
prom_getintdefault(sdev->bus->prom_node,
"scsi-initiator-id",
7);
of_getintprop_default(sdev->bus->ofdev.node,
"scsi-initiator-id",
7);
esp->ehost->this_id = esp->scsi_id;
esp->scsi_id_mask = (1 << esp->scsi_id);
......@@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff;
}
static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
struct sbus_dev *espdma, struct sbus_bus *sbus,
int id, int hme)
static int __init detect_one_esp(struct scsi_host_template *tpnt,
struct device *dev,
struct sbus_dev *esp_dev,
struct sbus_dev *espdma,
struct sbus_bus *sbus,
int hme)
{
struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
static int instance;
struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
struct esp *esp;
if (!esp_host) {
printk("ESP: Cannot register SCSI host\n");
return -1;
}
if (!esp_host)
return -ENOMEM;
if (hme)
esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host;
esp->sdev = esp_dev;
esp->esp_id = id;
esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name));
esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) {
......@@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp);
if (scsi_add_host(esp_host, dev))
goto fail_free_irq;
dev_set_drvdata(&esp_dev->ofdev.dev, esp);
scsi_scan_host(esp_host);
instance++;
return 0;
fail_free_irq:
free_irq(esp->ehost->irq, esp);
fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command,
......@@ -1129,119 +1107,101 @@ fail_dvma_release:
esp->dma->allocated = 0;
fail_unlink:
esp_chain_del(esp);
scsi_unregister(esp_host);
scsi_host_put(esp_host);
return -1;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version.
*/
static int __devexit esp_remove_common(struct esp *esp)
{
unsigned int irq = esp->ehost->irq;
scsi_remove_host(esp->ehost);
scsi_host_put(esp->ehost);
esp->ehost = NULL;
ESP_INTSOFF(esp->dregs);
#if 0
esp_reset_dma(esp);
esp_reset_esp(esp);
#endif
free_irq(irq, esp);
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command, esp->esp_command_dvma);
sbus_iounmap(esp->eregs, ESP_REG_SIZE);
esp->dma->allocated = 0;
kfree(esp);
return 0;
}
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
static int __init esp_detect(struct scsi_host_template *tpnt)
{
static struct sbus_dev esp_dev;
int esps_in_use = 0;
espchain = NULL;
static struct sbus_dev sun4_esp_dev;
static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
{
if (sun4_esp_physaddr) {
memset (&esp_dev, 0, sizeof(esp_dev));
esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
esp_dev.irqs[0] = 4;
esp_dev.resource[0].start = sun4_esp_physaddr;
esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
esp_dev.resource[0].flags = IORESOURCE_IO;
if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
esps_in_use++;
printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
esps_running = esps_in_use;
memset(&sun4_esp_dev, 0, sizeof(esp_dev));
sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
sun4_esp_dev.irqs[0] = 4;
sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
sun4_esp_dev.resource[0].end =
sun4_esp_physaddr + ESP_REG_SIZE - 1;
sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
return detect_one_esp(tpnt, NULL,
&sun4_esp_dev, NULL, NULL, 0);
}
return esps_in_use;
return 0;
}
#else /* !CONFIG_SUN4 */
static int __init esp_detect(struct scsi_host_template *tpnt)
static int __devexit esp_sun4_remove(void)
{
struct sbus_bus *sbus;
struct sbus_dev *esp_dev, *sbdev_iter;
int nesps = 0, esps_in_use = 0;
struct esp *esp = dev_get_drvdata(&dev->dev);
espchain = 0;
if (!sbus_root) {
#ifdef CONFIG_PCI
return 0;
#else
panic("No SBUS in esp_detect()");
#endif
}
for_each_sbus(sbus) {
for_each_sbusdev(sbdev_iter, sbus) {
struct sbus_dev *espdma = NULL;
int hme = 0;
/* Is it an esp sbus device? */
esp_dev = sbdev_iter;
if (strcmp(esp_dev->prom_name, "esp") &&
strcmp(esp_dev->prom_name, "SUNW,esp")) {
if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
hme = 1;
espdma = esp_dev;
} else {
if (!esp_dev->child ||
(strcmp(esp_dev->prom_name, "espdma") &&
strcmp(esp_dev->prom_name, "dma")))
continue; /* nope... */
espdma = esp_dev;
esp_dev = esp_dev->child;
if (strcmp(esp_dev->prom_name, "esp") &&
strcmp(esp_dev->prom_name, "SUNW,esp"))
continue; /* how can this happen? */
}
}
if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
continue;
esps_in_use++;
} /* for each sbusdev */
} /* for each sbus */
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
esps_in_use);
esps_running = esps_in_use;
return esps_in_use;
return esp_remove_common(esp);
}
#endif /* !CONFIG_SUN4 */
#else /* !CONFIG_SUN4 */
/*
*/
static int esp_release(struct Scsi_Host *host)
static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct esp *esp = (struct esp *) host->hostdata;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
struct sbus_dev *dma_sdev = NULL;
int hme = 0;
if (dp->parent &&
(!strcmp(dp->parent->name, "espdma") ||
!strcmp(dp->parent->name, "dma")))
dma_sdev = sdev->parent;
else if (!strcmp(dp->name, "SUNW,fas")) {
dma_sdev = sdev;
hme = 1;
}
ESP_INTSOFF(esp->dregs);
#if 0
esp_reset_dma(esp);
esp_reset_esp(esp);
#endif
return detect_one_esp(match->data, &dev->dev,
sdev, dma_sdev, sdev->bus, hme);
}
free_irq(esp->ehost->irq, esp);
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command, esp->esp_command_dvma);
sbus_iounmap(esp->eregs, ESP_REG_SIZE);
esp->dma->allocated = 0;
esp_chain_del(esp);
static int __devexit esp_sbus_remove(struct of_device *dev)
{
struct esp *esp = dev_get_drvdata(&dev->dev);
return 0;
return esp_remove_common(esp);
}
#endif /* !CONFIG_SUN4 */
/* The info function will return whatever useful
* information the developer sees fit. If not provided, then
* the name field will be used instead.
......@@ -1415,18 +1375,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout)
{
struct esp *esp;
struct esp *esp = (struct esp *) host->hostdata;
if (inout)
return -EINVAL; /* not yet */
for_each_esp(esp) {
if (esp->ehost == host)
break;
}
if (!esp)
return -EINVAL;
if (start)
*start = buffer;
......@@ -4377,15 +4330,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL;
}
static struct scsi_host_template driver_template = {
.proc_name = "esp",
.proc_info = esp_proc_info,
.name = "Sun ESP 100/100a/200",
.detect = esp_detect,
static struct scsi_host_template esp_template = {
.module = THIS_MODULE,
.name = "esp",
.info = esp_info,
.slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy,
.release = esp_release,
.info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
......@@ -4394,12 +4344,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
.proc_name = "esp",
.proc_info = esp_proc_info,
};
#ifndef CONFIG_SUN4
static struct of_device_id esp_match[] = {
{
.name = "SUNW,esp",
.data = &esp_template,
},
{
.name = "SUNW,fas",
.data = &esp_template,
},
{
.name = "esp",
.data = &esp_template,
},
{},
};
MODULE_DEVICE_TABLE(of, esp_match);
static struct of_platform_driver esp_sbus_driver = {
.name = "esp",
.match_table = esp_match,
.probe = esp_sbus_probe,
.remove = __devexit_p(esp_sbus_remove),
};
#endif
static int __init esp_init(void)
{
#ifdef CONFIG_SUN4
return esp_sun4_probe(&esp_template);
#else
return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
#endif
}
#include "scsi_module.c"
static void __exit esp_exit(void)
{
#ifdef CONFIG_SUN4
esp_sun4_remove();
#else
of_unregister_driver(&esp_sbus_driver);
#endif
}
MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
MODULE_DESCRIPTION("ESP Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(esp_init);
module_exit(esp_exit);
......@@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
/* For our interrupt engine. */
#define for_each_esp(esp) \
for((esp) = espchain; (esp); (esp) = (esp)->next)
#endif /* !(_SPARC_ESP_H) */
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