X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fscsi%2Fesp.c;fp=drivers%2Fscsi%2Fesp.c;h=87a8c3d2072c4011009d53b7c2dd43e72ba6b4f4;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=5630868c1b252f21f1a709890f1691e3be25d59b;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 5630868c1..87a8c3d20 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1,6 +1,7 @@ -/* esp.c: ESP Sun SCSI driver. +/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $ + * esp.c: EnhancedScsiProcessor Sun SCSI driver code. * - * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) */ /* TODO: @@ -12,6 +13,7 @@ * 3) Add tagged queueing. */ +#include #include #include #include @@ -183,6 +185,11 @@ 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); @@ -687,6 +694,36 @@ 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; @@ -778,14 +815,14 @@ static int __init esp_register_irq(struct esp *esp) * sanely maintain. */ if (request_irq(esp->ehost->irq, esp_intr, - IRQF_SHARED, "ESP SCSI", esp)) { + SA_SHIRQ, "ESP SCSI", esp)) { printk("esp%d: Cannot acquire irq line\n", esp->esp_id); return -1; } - printk("esp%d: IRQ %d ", esp->esp_id, - esp->ehost->irq); + printk("esp%d: IRQ %s ", esp->esp_id, + __irq_itoa(esp->ehost->irq)); return 0; } @@ -793,20 +830,19 @@ 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 = of_getintprop_default(dp, - "initiator-id", - -1); + esp->scsi_id = prom_getintdefault(esp->prom_node, + "initiator-id", + -1); if (esp->scsi_id == -1) - esp->scsi_id = of_getintprop_default(dp, - "scsi-initiator-id", - -1); + esp->scsi_id = prom_getintdefault(esp->prom_node, + "scsi-initiator-id", + -1); if (esp->scsi_id == -1) esp->scsi_id = (sdev->bus == NULL) ? 7 : - of_getintprop_default(sdev->bus->ofdev.node, - "scsi-initiator-id", - 7); + prom_getintdefault(sdev->bus->prom_node, + "scsi-initiator-id", + 7); esp->ehost->this_id = esp->scsi_id; esp->scsi_id_mask = (1 << esp->scsi_id); @@ -1031,30 +1067,28 @@ 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 device *dev, - struct sbus_dev *esp_dev, - struct sbus_dev *espdma, - struct sbus_bus *sbus, - int hme) +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 instance; - struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp)); + struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp)); struct esp *esp; - if (!esp_host) - return -ENOMEM; - + if (!esp_host) { + printk("ESP: Cannot register SCSI host\n"); + return -1; + } if (hme) esp_host->max_id = 16; esp = (struct esp *) esp_host->hostdata; esp->ehost = esp_host; esp->sdev = esp_dev; - esp->esp_id = instance; + esp->esp_id = id; 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) { @@ -1081,19 +1115,8 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, 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, @@ -1106,99 +1129,119 @@ fail_dvma_release: esp->dma->allocated = 0; fail_unlink: - scsi_host_put(esp_host); + esp_chain_del(esp); + scsi_unregister(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); - - 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; - - scsi_host_put(esp->ehost); - - return 0; -} - #ifdef CONFIG_SUN4 #include -static struct sbus_dev sun4_esp_dev; - -static int __init esp_sun4_probe(struct scsi_host_template *tpnt) +static int __init esp_detect(struct scsi_host_template *tpnt) { + static struct sbus_dev esp_dev; + int esps_in_use = 0; + + espchain = NULL; + if (sun4_esp_physaddr) { - memset(&sun4_esp_dev, 0, sizeof(sun4_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); + 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; } - return 0; + return esps_in_use; } -static int __devexit esp_sun4_remove(void) +#else /* !CONFIG_SUN4 */ + +static int __init esp_detect(struct scsi_host_template *tpnt) { - struct of_device *dev = &sun4_esp_dev.ofdev; - struct esp *esp = dev_get_drvdata(&dev->dev); + struct sbus_bus *sbus; + struct sbus_dev *esp_dev, *sbdev_iter; + int nesps = 0, esps_in_use = 0; - return esp_remove_common(esp); + 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; } -#else /* !CONFIG_SUN4 */ +#endif /* !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 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; - } + struct esp *esp = (struct esp *) host->hostdata; - return detect_one_esp(match->data, &dev->dev, - sdev, dma_sdev, sdev->bus, hme); -} + ESP_INTSOFF(esp->dregs); +#if 0 + esp_reset_dma(esp); + esp_reset_esp(esp); +#endif -static int __devexit esp_sbus_remove(struct of_device *dev) -{ - struct esp *esp = dev_get_drvdata(&dev->dev); + 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); - return esp_remove_common(esp); + return 0; } -#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. @@ -1372,11 +1415,18 @@ 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 *) host->hostdata; + struct esp *esp; if (inout) return -EINVAL; /* not yet */ + for_each_esp(esp) { + if (esp->ehost == host) + break; + } + if (!esp) + return -EINVAL; + if (start) *start = buffer; @@ -1398,7 +1448,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp) sp->SCp.ptr = NULL; } } else { - sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffer = (struct scatterlist *) sp->buffer; sp->SCp.buffers_residual = sbus_map_sg(esp->sdev, sp->SCp.buffer, sp->use_sg, @@ -1411,7 +1461,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp) static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp) { if (sp->use_sg) { - sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg, + sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg, sp->sc_data_direction); } else if (sp->request_bufflen) { sbus_unmap_single(esp->sdev, @@ -2755,15 +2805,18 @@ static int esp_do_data_finale(struct esp *esp) */ static int esp_should_clear_sync(struct scsi_cmnd *sp) { - u8 cmd = sp->cmnd[0]; + u8 cmd1 = sp->cmnd[0]; + u8 cmd2 = sp->data_cmnd[0]; /* These cases are for spinning up a disk and * waiting for that spinup to complete. */ - if (cmd == START_STOP) + if (cmd1 == START_STOP || + cmd2 == START_STOP) return 0; - if (cmd == TEST_UNIT_READY) + if (cmd1 == TEST_UNIT_READY || + cmd2 == TEST_UNIT_READY) return 0; /* One more special case for SCSI tape drives, @@ -2771,7 +2824,8 @@ static int esp_should_clear_sync(struct scsi_cmnd *sp) * completion of a rewind or tape load operation. */ if (sp->device->type == TYPE_TAPE) { - if (cmd == MODE_SENSE) + if (cmd1 == MODE_SENSE || + cmd2 == MODE_SENSE) return 0; } @@ -4323,12 +4377,15 @@ static void esp_slave_destroy(struct scsi_device *SDptr) SDptr->hostdata = NULL; } -static struct scsi_host_template esp_template = { - .module = THIS_MODULE, - .name = "esp", - .info = esp_info, +static struct scsi_host_template driver_template = { + .proc_name = "esp", + .proc_info = esp_proc_info, + .name = "Sun ESP 100/100a/200", + .detect = esp_detect, .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, @@ -4337,58 +4394,12 @@ static struct scsi_host_template esp_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 -} -static void __exit esp_exit(void) -{ -#ifdef CONFIG_SUN4 - esp_sun4_remove(); -#else - of_unregister_driver(&esp_sbus_driver); -#endif -} +#include "scsi_module.c" -MODULE_DESCRIPTION("ESP Sun SCSI driver"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver"); +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -module_init(esp_init); -module_exit(esp_exit);