diff options
Diffstat (limited to 'drivers/scsi/ipr.c')
-rw-r--r-- | drivers/scsi/ipr.c | 138 |
1 files changed, 117 insertions, 21 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0f8bc772b112..5f045505a1f4 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c | |||
@@ -131,13 +131,13 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { | |||
131 | }; | 131 | }; |
132 | 132 | ||
133 | static const struct ipr_chip_t ipr_chip[] = { | 133 | static const struct ipr_chip_t ipr_chip[] = { |
134 | { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] }, | 134 | { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, &ipr_chip_cfg[0] }, |
135 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] }, | 135 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, &ipr_chip_cfg[0] }, |
136 | { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] }, | 136 | { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] }, |
137 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] }, | 137 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] }, |
138 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] }, | 138 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, &ipr_chip_cfg[0] }, |
139 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] }, | 139 | { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, &ipr_chip_cfg[1] }, |
140 | { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] } | 140 | { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, &ipr_chip_cfg[1] } |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static int ipr_max_bus_speeds [] = { | 143 | static int ipr_max_bus_speeds [] = { |
@@ -7367,6 +7367,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, | |||
7367 | INIT_LIST_HEAD(&ioa_cfg->used_res_q); | 7367 | INIT_LIST_HEAD(&ioa_cfg->used_res_q); |
7368 | INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); | 7368 | INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); |
7369 | init_waitqueue_head(&ioa_cfg->reset_wait_q); | 7369 | init_waitqueue_head(&ioa_cfg->reset_wait_q); |
7370 | init_waitqueue_head(&ioa_cfg->msi_wait_q); | ||
7370 | ioa_cfg->sdt_state = INACTIVE; | 7371 | ioa_cfg->sdt_state = INACTIVE; |
7371 | if (ipr_enable_cache) | 7372 | if (ipr_enable_cache) |
7372 | ioa_cfg->cache_state = CACHE_ENABLED; | 7373 | ioa_cfg->cache_state = CACHE_ENABLED; |
@@ -7398,25 +7399,108 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, | |||
7398 | } | 7399 | } |
7399 | 7400 | ||
7400 | /** | 7401 | /** |
7401 | * ipr_get_chip_cfg - Find adapter chip configuration | 7402 | * ipr_get_chip_info - Find adapter chip information |
7402 | * @dev_id: PCI device id struct | 7403 | * @dev_id: PCI device id struct |
7403 | * | 7404 | * |
7404 | * Return value: | 7405 | * Return value: |
7405 | * ptr to chip config on success / NULL on failure | 7406 | * ptr to chip information on success / NULL on failure |
7406 | **/ | 7407 | **/ |
7407 | static const struct ipr_chip_cfg_t * __devinit | 7408 | static const struct ipr_chip_t * __devinit |
7408 | ipr_get_chip_cfg(const struct pci_device_id *dev_id) | 7409 | ipr_get_chip_info(const struct pci_device_id *dev_id) |
7409 | { | 7410 | { |
7410 | int i; | 7411 | int i; |
7411 | 7412 | ||
7412 | for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) | 7413 | for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) |
7413 | if (ipr_chip[i].vendor == dev_id->vendor && | 7414 | if (ipr_chip[i].vendor == dev_id->vendor && |
7414 | ipr_chip[i].device == dev_id->device) | 7415 | ipr_chip[i].device == dev_id->device) |
7415 | return ipr_chip[i].cfg; | 7416 | return &ipr_chip[i]; |
7416 | return NULL; | 7417 | return NULL; |
7417 | } | 7418 | } |
7418 | 7419 | ||
7419 | /** | 7420 | /** |
7421 | * ipr_test_intr - Handle the interrupt generated in ipr_test_msi(). | ||
7422 | * @pdev: PCI device struct | ||
7423 | * | ||
7424 | * Description: Simply set the msi_received flag to 1 indicating that | ||
7425 | * Message Signaled Interrupts are supported. | ||
7426 | * | ||
7427 | * Return value: | ||
7428 | * 0 on success / non-zero on failure | ||
7429 | **/ | ||
7430 | static irqreturn_t __devinit ipr_test_intr(int irq, void *devp) | ||
7431 | { | ||
7432 | struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; | ||
7433 | unsigned long lock_flags = 0; | ||
7434 | irqreturn_t rc = IRQ_HANDLED; | ||
7435 | |||
7436 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | ||
7437 | |||
7438 | ioa_cfg->msi_received = 1; | ||
7439 | wake_up(&ioa_cfg->msi_wait_q); | ||
7440 | |||
7441 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | ||
7442 | return rc; | ||
7443 | } | ||
7444 | |||
7445 | /** | ||
7446 | * ipr_test_msi - Test for Message Signaled Interrupt (MSI) support. | ||
7447 | * @pdev: PCI device struct | ||
7448 | * | ||
7449 | * Description: The return value from pci_enable_msi() can not always be | ||
7450 | * trusted. This routine sets up and initiates a test interrupt to determine | ||
7451 | * if the interrupt is received via the ipr_test_intr() service routine. | ||
7452 | * If the tests fails, the driver will fall back to LSI. | ||
7453 | * | ||
7454 | * Return value: | ||
7455 | * 0 on success / non-zero on failure | ||
7456 | **/ | ||
7457 | static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, | ||
7458 | struct pci_dev *pdev) | ||
7459 | { | ||
7460 | int rc; | ||
7461 | volatile u32 int_reg; | ||
7462 | unsigned long lock_flags = 0; | ||
7463 | |||
7464 | ENTER; | ||
7465 | |||
7466 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | ||
7467 | init_waitqueue_head(&ioa_cfg->msi_wait_q); | ||
7468 | ioa_cfg->msi_received = 0; | ||
7469 | ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); | ||
7470 | writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg); | ||
7471 | int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); | ||
7472 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | ||
7473 | |||
7474 | rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg); | ||
7475 | if (rc) { | ||
7476 | dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq); | ||
7477 | return rc; | ||
7478 | } else if (ipr_debug) | ||
7479 | dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq); | ||
7480 | |||
7481 | writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg); | ||
7482 | int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); | ||
7483 | wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ); | ||
7484 | ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); | ||
7485 | |||
7486 | spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); | ||
7487 | if (!ioa_cfg->msi_received) { | ||
7488 | /* MSI test failed */ | ||
7489 | dev_info(&pdev->dev, "MSI test failed. Falling back to LSI.\n"); | ||
7490 | rc = -EOPNOTSUPP; | ||
7491 | } else if (ipr_debug) | ||
7492 | dev_info(&pdev->dev, "MSI test succeeded.\n"); | ||
7493 | |||
7494 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | ||
7495 | |||
7496 | free_irq(pdev->irq, ioa_cfg); | ||
7497 | |||
7498 | LEAVE; | ||
7499 | |||
7500 | return rc; | ||
7501 | } | ||
7502 | |||
7503 | /** | ||
7420 | * ipr_probe_ioa - Allocates memory and does first stage of initialization | 7504 | * ipr_probe_ioa - Allocates memory and does first stage of initialization |
7421 | * @pdev: PCI device struct | 7505 | * @pdev: PCI device struct |
7422 | * @dev_id: PCI device id struct | 7506 | * @dev_id: PCI device id struct |
@@ -7441,11 +7525,6 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, | |||
7441 | goto out; | 7525 | goto out; |
7442 | } | 7526 | } |
7443 | 7527 | ||
7444 | if (!(rc = pci_enable_msi(pdev))) | ||
7445 | dev_info(&pdev->dev, "MSI enabled\n"); | ||
7446 | else if (ipr_debug) | ||
7447 | dev_info(&pdev->dev, "Cannot enable MSI\n"); | ||
7448 | |||
7449 | dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); | 7528 | dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); |
7450 | 7529 | ||
7451 | host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); | 7530 | host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); |
@@ -7461,14 +7540,16 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, | |||
7461 | ata_host_init(&ioa_cfg->ata_host, &pdev->dev, | 7540 | ata_host_init(&ioa_cfg->ata_host, &pdev->dev, |
7462 | sata_port_info.flags, &ipr_sata_ops); | 7541 | sata_port_info.flags, &ipr_sata_ops); |
7463 | 7542 | ||
7464 | ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id); | 7543 | ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id); |
7465 | 7544 | ||
7466 | if (!ioa_cfg->chip_cfg) { | 7545 | if (!ioa_cfg->ipr_chip) { |
7467 | dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n", | 7546 | dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n", |
7468 | dev_id->vendor, dev_id->device); | 7547 | dev_id->vendor, dev_id->device); |
7469 | goto out_scsi_host_put; | 7548 | goto out_scsi_host_put; |
7470 | } | 7549 | } |
7471 | 7550 | ||
7551 | ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg; | ||
7552 | |||
7472 | if (ipr_transop_timeout) | 7553 | if (ipr_transop_timeout) |
7473 | ioa_cfg->transop_timeout = ipr_transop_timeout; | 7554 | ioa_cfg->transop_timeout = ipr_transop_timeout; |
7474 | else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT) | 7555 | else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT) |
@@ -7519,6 +7600,18 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, | |||
7519 | goto cleanup_nomem; | 7600 | goto cleanup_nomem; |
7520 | } | 7601 | } |
7521 | 7602 | ||
7603 | /* Enable MSI style interrupts if they are supported. */ | ||
7604 | if (ioa_cfg->ipr_chip->intr_type == IPR_USE_MSI && !pci_enable_msi(pdev)) { | ||
7605 | rc = ipr_test_msi(ioa_cfg, pdev); | ||
7606 | if (rc == -EOPNOTSUPP) | ||
7607 | pci_disable_msi(pdev); | ||
7608 | else if (rc) | ||
7609 | goto out_msi_disable; | ||
7610 | else | ||
7611 | dev_info(&pdev->dev, "MSI enabled with IRQ: %d\n", pdev->irq); | ||
7612 | } else if (ipr_debug) | ||
7613 | dev_info(&pdev->dev, "Cannot enable MSI.\n"); | ||
7614 | |||
7522 | /* Save away PCI config space for use following IOA reset */ | 7615 | /* Save away PCI config space for use following IOA reset */ |
7523 | rc = pci_save_state(pdev); | 7616 | rc = pci_save_state(pdev); |
7524 | 7617 | ||
@@ -7556,7 +7649,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, | |||
7556 | ioa_cfg->ioa_unit_checked = 1; | 7649 | ioa_cfg->ioa_unit_checked = 1; |
7557 | 7650 | ||
7558 | ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); | 7651 | ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); |
7559 | rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg); | 7652 | rc = request_irq(pdev->irq, ipr_isr, |
7653 | ioa_cfg->msi_received ? 0 : IRQF_SHARED, | ||
7654 | IPR_NAME, ioa_cfg); | ||
7560 | 7655 | ||
7561 | if (rc) { | 7656 | if (rc) { |
7562 | dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", | 7657 | dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", |
@@ -7583,12 +7678,13 @@ cleanup_nolog: | |||
7583 | ipr_free_mem(ioa_cfg); | 7678 | ipr_free_mem(ioa_cfg); |
7584 | cleanup_nomem: | 7679 | cleanup_nomem: |
7585 | iounmap(ipr_regs); | 7680 | iounmap(ipr_regs); |
7681 | out_msi_disable: | ||
7682 | pci_disable_msi(pdev); | ||
7586 | out_release_regions: | 7683 | out_release_regions: |
7587 | pci_release_regions(pdev); | 7684 | pci_release_regions(pdev); |
7588 | out_scsi_host_put: | 7685 | out_scsi_host_put: |
7589 | scsi_host_put(host); | 7686 | scsi_host_put(host); |
7590 | out_disable: | 7687 | out_disable: |
7591 | pci_disable_msi(pdev); | ||
7592 | pci_disable_device(pdev); | 7688 | pci_disable_device(pdev); |
7593 | goto out; | 7689 | goto out; |
7594 | } | 7690 | } |