Skip to content

Commit

Permalink
ncr5380: Fix SCSI_IRQ_NONE bugs
Browse files Browse the repository at this point in the history
Oak scsi doesn't use any IRQ, but it sets irq = IRQ_NONE rather than
SCSI_IRQ_NONE. Problem is, the core NCR5380 driver expects SCSI_IRQ_NONE
if it is to issue IDENTIFY commands that prevent target disconnection.
And, as Geert points out, IRQ_NONE is part of enum irqreturn.

Other drivers, when they can't get an IRQ or can't use one, will set
host->irq = SCSI_IRQ_NONE (that is, 255). But when they exit they will
attempt to free IRQ 255 which was never requested.

Fix these bugs by using NO_IRQ in place of SCSI_IRQ_NONE and IRQ_NONE.
That means IRQ 0 is no longer probed by ISA drivers but I don't think
this matters.

Setting IRQ = 255 for these ISA drivers is understood to mean no IRQ.
This remains supported so as to avoid breaking existing ISA setups (which
can be difficult to get working) and because existing documentation
(SANE, TLDP etc) describes this usage for the ISA NCR5380 driver options.

Signed-off-by: Finn Thain <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Tested-by: Michael Schmitz <[email protected]>
Signed-off-by: Christoph Hellwig <[email protected]>
  • Loading branch information
Finn Thain authored and Christoph Hellwig committed Nov 20, 2014
1 parent 3f9e986 commit 22f5f10
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 48 deletions.
12 changes: 6 additions & 6 deletions drivers/scsi/NCR5380.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,12 +574,12 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
int trying_irqs, i, mask;
NCR5380_setup(instance);

for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
trying_irqs |= mask;

timeout = jiffies + (250 * HZ / 1000);
probe_irq = SCSI_IRQ_NONE;
probe_irq = NO_IRQ;

/*
* A interrupt is triggered whenever BSY = false, SEL = true
Expand All @@ -596,13 +596,13 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);

while (probe_irq == SCSI_IRQ_NONE && time_before(jiffies, timeout))
while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
schedule_timeout_uninterruptible(1);

NCR5380_write(SELECT_ENABLE_REG, 0);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);

for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)
for (i = 1, mask = 2; i < 16; ++i, mask <<= 1)
if (trying_irqs & mask)
free_irq(i, NULL);

Expand Down Expand Up @@ -730,7 +730,7 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,

SPRINTF("\nBase Addr: 0x%05lX ", (long) instance->base);
SPRINTF("io_port: %04x ", (int) instance->io_port);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
SPRINTF("IRQ: None.\n");
else
SPRINTF("IRQ: %d.\n", instance->irq);
Expand Down Expand Up @@ -1501,7 +1501,7 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd)
}

dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun);
tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);

len = 1;
cmd->tag = 0;
Expand Down
5 changes: 4 additions & 1 deletion drivers/scsi/NCR5380.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,15 @@
* Scsi_Host structure
*/

#define SCSI_IRQ_NONE 255
#define DMA_NONE 255
#define IRQ_AUTO 254
#define DMA_AUTO 254
#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */

#ifndef NO_IRQ
#define NO_IRQ 0
#endif

#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */
#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */
#define FLAG_NCR53C400 4 /* NCR53c400 */
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/arm/oak.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
goto unreg;
}

host->irq = IRQ_NONE;
host->irq = NO_IRQ;
host->n_io_port = 255;

NCR5380_init(host, 0);
Expand Down
7 changes: 4 additions & 3 deletions drivers/scsi/dmx3191d.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
*/
printk(KERN_WARNING "dmx3191: IRQ %d not available - "
"switching to polled mode.\n", pdev->irq);
shost->irq = SCSI_IRQ_NONE;
shost->irq = NO_IRQ;
}

pci_set_drvdata(pdev, shost);
Expand All @@ -113,7 +113,8 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
return 0;

out_free_irq:
free_irq(shost->irq, shost);
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
out_release_region:
release_region(io, DMX3191D_REGION_LEN);
out_disable_device:
Expand All @@ -130,7 +131,7 @@ static void dmx3191d_remove_one(struct pci_dev *pdev)

NCR5380_exit(shost);

if (shost->irq != SCSI_IRQ_NONE)
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
release_region(shost->io_port, DMX3191D_REGION_LEN);
pci_disable_device(pdev);
Expand Down
22 changes: 13 additions & 9 deletions drivers/scsi/dtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,31 +254,35 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
else
instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);

/* Compatibility with documented NCR5380 kernel parameters */
if (instance->irq == 255)
instance->irq = NO_IRQ;

#ifndef DONT_USE_INTR
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
if (instance->irq != SCSI_IRQ_NONE)
if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, dtc_intr, 0,
"dtc", instance)) {
printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
}

if (instance->irq == SCSI_IRQ_NONE) {
if (instance->irq == NO_IRQ) {
printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
#else
if (instance->irq != SCSI_IRQ_NONE)
if (instance->irq != NO_IRQ)
printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
#endif
#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
#endif

printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
printk(" interrupts disabled");
else
printk(" irq %d", instance->irq);
Expand Down Expand Up @@ -350,7 +354,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
i = 0;
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
else
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
Expand Down Expand Up @@ -401,7 +405,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
/* set direction (write) */
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, 0);
else
NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
Expand Down Expand Up @@ -440,7 +444,7 @@ static int dtc_release(struct Scsi_Host *shost)
{
NCR5380_local_declare();
NCR5380_setup(shost);
if (shost->irq)
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
if (shost->io_port && shost->n_io_port)
Expand Down
18 changes: 11 additions & 7 deletions drivers/scsi/g_NCR5380.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
if (pnp_irq_valid(dev, 0))
overrides[count].irq = pnp_irq(dev, 0);
else
overrides[count].irq = SCSI_IRQ_NONE;
overrides[count].irq = NO_IRQ;
if (pnp_dma_valid(dev, 0))
overrides[count].dma = pnp_dma(dev, 0);
else
Expand Down Expand Up @@ -432,20 +432,24 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
else
instance->irq = NCR5380_probe_irq(instance, 0xffff);

if (instance->irq != SCSI_IRQ_NONE)
/* Compatibility with documented NCR5380 kernel parameters */
if (instance->irq == 255)
instance->irq = NO_IRQ;

if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, generic_NCR5380_intr,
0, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
}

if (instance->irq == SCSI_IRQ_NONE) {
if (instance->irq == NO_IRQ) {
printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}

printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
printk(" interrupts disabled");
else
printk(" irq %d", instance->irq);
Expand Down Expand Up @@ -486,7 +490,7 @@ static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
NCR5380_local_declare();
NCR5380_setup(instance);

if (instance->irq != SCSI_IRQ_NONE)
if (instance->irq != NO_IRQ)
free_irq(instance->irq, instance);
NCR5380_exit(instance);

Expand Down Expand Up @@ -796,7 +800,7 @@ static int generic_NCR5380_show_info(struct seq_file *m, struct Scsi_Host *scsi_
PRINTP("NO NCR53C400 driver extensions\n");
#endif
PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
if (scsi_ptr->irq == SCSI_IRQ_NONE)
if (scsi_ptr->irq == NO_IRQ)
PRINTP("no interrupt\n");
else
PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
Expand Down
8 changes: 4 additions & 4 deletions drivers/scsi/mac_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,15 @@ int __init macscsi_detect(struct scsi_host_template * tpnt)

instance->n_io_port = 255;

if (instance->irq != SCSI_IRQ_NONE)
if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, NCR5380_intr, 0, "ncr5380", instance)) {
printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
}

printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
printk (KERN_INFO "s disabled");
else
printk (KERN_INFO " %d", instance->irq);
Expand All @@ -252,7 +252,7 @@ int __init macscsi_detect(struct scsi_host_template * tpnt)

int macscsi_release (struct Scsi_Host *shpnt)
{
if (shpnt->irq != SCSI_IRQ_NONE)
if (shpnt->irq != NO_IRQ)
free_irq(shpnt->irq, shpnt);
NCR5380_exit(shpnt);

Expand Down
20 changes: 11 additions & 9 deletions drivers/scsi/pas16.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,11 @@
* If you have problems with your card not being recognized, use
* the LILO command line override. Try to get it recognized without
* interrupts. Ie, for a board at the default 0x388 base port,
* boot: linux pas16=0x388,255
* boot: linux pas16=0x388,0
*
* SCSI_IRQ_NONE (255) should be specified for no interrupt,
* NO_IRQ (0) should be specified for no interrupt,
* IRQ_AUTO (254) to autoprobe for an IRQ line if overridden
* on the command line.
*
* (IRQ_AUTO == 254, SCSI_IRQ_NONE == 255 in NCR5380.h)
*/

#include <linux/module.h>
Expand Down Expand Up @@ -416,15 +414,19 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
else
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);

if (instance->irq != SCSI_IRQ_NONE)
/* Compatibility with documented NCR5380 kernel parameters */
if (instance->irq == 255)
instance->irq = NO_IRQ;

if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, pas16_intr, 0,
"pas16", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
}

if (instance->irq == SCSI_IRQ_NONE) {
if (instance->irq == NO_IRQ) {
printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
/* Disable 5380 interrupts, leave drive params the same */
Expand All @@ -438,7 +440,7 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)

printk("scsi%d : at 0x%04x", instance->host_no, (int)
instance->io_port);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
printk (" interrupts disabled");
else
printk (" irq %d", instance->irq);
Expand Down Expand Up @@ -568,7 +570,7 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src

static int pas16_release(struct Scsi_Host *shost)
{
if (shost->irq)
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
if (shost->io_port && shost->n_io_port)
Expand Down
6 changes: 3 additions & 3 deletions drivers/scsi/sun3_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ static int __init sun3scsi_detect(struct scsi_host_template *tpnt)
#ifndef REAL_DMA
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
#else
printk("scsi%d: IRQ%d not free, bailing out\n",
instance->host_no, instance->irq);
Expand All @@ -288,7 +288,7 @@ static int __init sun3scsi_detect(struct scsi_host_template *tpnt)

pr_info("scsi%d: %s at port %lX irq", instance->host_no,
tpnt->proc_name, instance->io_port);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
printk ("s disabled");
else
printk (" %d", instance->irq);
Expand Down Expand Up @@ -325,7 +325,7 @@ static int __init sun3scsi_detect(struct scsi_host_template *tpnt)

static int sun3scsi_release(struct Scsi_Host *shpnt)
{
if (shpnt->irq != SCSI_IRQ_NONE)
if (shpnt->irq != NO_IRQ)
free_irq(shpnt->irq, shpnt);

iounmap((void *)sun3_scsi_regp);
Expand Down
14 changes: 9 additions & 5 deletions drivers/scsi/t128.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,15 +228,19 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
else
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);

if (instance->irq != SCSI_IRQ_NONE)
/* Compatibility with documented NCR5380 kernel parameters */
if (instance->irq == 255)
instance->irq = NO_IRQ;

if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, t128_intr, 0, "t128",
instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
instance->irq = NO_IRQ;
}

if (instance->irq == SCSI_IRQ_NONE) {
if (instance->irq == NO_IRQ) {
printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
Expand All @@ -246,7 +250,7 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
#endif

printk("scsi%d : at 0x%08lx", instance->host_no, instance->base);
if (instance->irq == SCSI_IRQ_NONE)
if (instance->irq == NO_IRQ)
printk (" interrupts disabled");
else
printk (" irq %d", instance->irq);
Expand All @@ -265,7 +269,7 @@ static int t128_release(struct Scsi_Host *shost)
{
NCR5380_local_declare();
NCR5380_setup(shost);
if (shost->irq)
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
if (shost->io_port && shost->n_io_port)
Expand Down

0 comments on commit 22f5f10

Please sign in to comment.