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: ESP Sun SCSI driver.
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
* *
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/ */
/* TODO: /* TODO:
...@@ -185,11 +184,6 @@ enum { ...@@ -185,11 +184,6 @@ enum {
/*5*/ do_intr_end /*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. */ /* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); 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) ...@@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT); 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) static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{ {
struct sbus_dev *sdev = esp->sdev; struct sbus_dev *sdev = esp->sdev;
...@@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp) ...@@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp) static void __init esp_get_scsi_id(struct esp *esp)
{ {
struct sbus_dev *sdev = esp->sdev; struct sbus_dev *sdev = esp->sdev;
struct device_node *dp = sdev->ofdev.node;
esp->scsi_id = prom_getintdefault(esp->prom_node, esp->scsi_id = of_getintprop_default(dp,
"initiator-id", "initiator-id",
-1); -1);
if (esp->scsi_id == -1) if (esp->scsi_id == -1)
esp->scsi_id = prom_getintdefault(esp->prom_node, esp->scsi_id = of_getintprop_default(dp,
"scsi-initiator-id", "scsi-initiator-id",
-1); -1);
if (esp->scsi_id == -1) if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 : esp->scsi_id = (sdev->bus == NULL) ? 7 :
prom_getintdefault(sdev->bus->prom_node, of_getintprop_default(sdev->bus->ofdev.node,
"scsi-initiator-id", "scsi-initiator-id",
7); 7);
esp->ehost->this_id = esp->scsi_id; esp->ehost->this_id = esp->scsi_id;
esp->scsi_id_mask = (1 << esp->scsi_id); esp->scsi_id_mask = (1 << esp->scsi_id);
...@@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp) ...@@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff; esp->prev_hme_dmacsr = 0xffffffff;
} }
static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev, static int __init detect_one_esp(struct scsi_host_template *tpnt,
struct sbus_dev *espdma, struct sbus_bus *sbus, struct device *dev,
int id, int hme) 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; struct esp *esp;
if (!esp_host) { if (!esp_host)
printk("ESP: Cannot register SCSI host\n"); return -ENOMEM;
return -1;
}
if (hme) if (hme)
esp_host->max_id = 16; esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata; esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host; esp->ehost = esp_host;
esp->sdev = esp_dev; esp->sdev = esp_dev;
esp->esp_id = id; esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node; esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name, prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name)); sizeof(esp->prom_name));
esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0) if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink; goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) { 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 ...@@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp); 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; return 0;
fail_free_irq:
free_irq(esp->ehost->irq, esp);
fail_unmap_cmdarea: fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16, sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command, (void *) esp->esp_command,
...@@ -1129,119 +1107,101 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de ...@@ -1129,119 +1107,101 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp->dma->allocated = 0; esp->dma->allocated = 0;
fail_unlink: fail_unlink:
esp_chain_del(esp); scsi_host_put(esp_host);
scsi_unregister(esp_host);
return -1; return -1;
} }
/* Detecting ESP chips on the machine. This is the simple and easy /* Detecting ESP chips on the machine. This is the simple and easy
* version. * 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 #ifdef CONFIG_SUN4
#include <asm/sun4paddr.h> #include <asm/sun4paddr.h>
static int __init esp_detect(struct scsi_host_template *tpnt) static struct sbus_dev sun4_esp_dev;
{
static struct sbus_dev esp_dev;
int esps_in_use = 0;
espchain = NULL;
static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
{
if (sun4_esp_physaddr) { if (sun4_esp_physaddr) {
memset (&esp_dev, 0, sizeof(esp_dev)); memset(&sun4_esp_dev, 0, sizeof(esp_dev));
esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
esp_dev.irqs[0] = 4; sun4_esp_dev.irqs[0] = 4;
esp_dev.resource[0].start = sun4_esp_physaddr; sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1; sun4_esp_dev.resource[0].end =
esp_dev.resource[0].flags = IORESOURCE_IO; sun4_esp_physaddr + ESP_REG_SIZE - 1;
sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
esps_in_use++; return detect_one_esp(tpnt, NULL,
printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use); &sun4_esp_dev, NULL, NULL, 0);
esps_running = esps_in_use;
} }
return esps_in_use; return 0;
} }
#else /* !CONFIG_SUN4 */ static int __devexit esp_sun4_remove(void)
static int __init esp_detect(struct scsi_host_template *tpnt)
{ {
struct sbus_bus *sbus; struct esp *esp = dev_get_drvdata(&dev->dev);
struct sbus_dev *esp_dev, *sbdev_iter;
int nesps = 0, esps_in_use = 0;
espchain = 0; return esp_remove_common(esp);
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;
} }
#endif /* !CONFIG_SUN4 */ #else /* !CONFIG_SUN4 */
/* static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
*/
static int esp_release(struct Scsi_Host *host)
{ {
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); return detect_one_esp(match->data, &dev->dev,
#if 0 sdev, dma_sdev, sdev->bus, hme);
esp_reset_dma(esp); }
esp_reset_esp(esp);
#endif
free_irq(esp->ehost->irq, esp); static int __devexit esp_sbus_remove(struct of_device *dev)
sbus_free_consistent(esp->sdev, 16, {
(void *) esp->esp_command, esp->esp_command_dvma); struct esp *esp = dev_get_drvdata(&dev->dev);
sbus_iounmap(esp->eregs, ESP_REG_SIZE);
esp->dma->allocated = 0;
esp_chain_del(esp);
return 0; return esp_remove_common(esp);
} }
#endif /* !CONFIG_SUN4 */
/* The info function will return whatever useful /* The info function will return whatever useful
* information the developer sees fit. If not provided, then * information the developer sees fit. If not provided, then
* the name field will be used instead. * 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) ...@@ -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, static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout) int length, int inout)
{ {
struct esp *esp; struct esp *esp = (struct esp *) host->hostdata;
if (inout) if (inout)
return -EINVAL; /* not yet */ return -EINVAL; /* not yet */
for_each_esp(esp) {
if (esp->ehost == host)
break;
}
if (!esp)
return -EINVAL;
if (start) if (start)
*start = buffer; *start = buffer;
...@@ -4377,15 +4330,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr) ...@@ -4377,15 +4330,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL; SDptr->hostdata = NULL;
} }
static struct scsi_host_template driver_template = { static struct scsi_host_template esp_template = {
.proc_name = "esp", .module = THIS_MODULE,
.proc_info = esp_proc_info, .name = "esp",
.name = "Sun ESP 100/100a/200", .info = esp_info,
.detect = esp_detect,
.slave_alloc = esp_slave_alloc, .slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy, .slave_destroy = esp_slave_destroy,
.release = esp_release,
.info = esp_info,
.queuecommand = esp_queue, .queuecommand = esp_queue,
.eh_abort_handler = esp_abort, .eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset, .eh_bus_reset_handler = esp_reset,
...@@ -4394,12 +4344,58 @@ static struct scsi_host_template driver_template = { ...@@ -4394,12 +4344,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL, .sg_tablesize = SG_ALL,
.cmd_per_lun = 1, .cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING, .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_DESCRIPTION("ESP Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
module_init(esp_init);
module_exit(esp_exit);
...@@ -403,8 +403,4 @@ struct esp { ...@@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) #define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 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) */ #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