diff options
-rw-r--r-- | drivers/block/cciss.c | 73 |
1 files changed, 15 insertions, 58 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index fd08644bf2a0..2e547bddc5a7 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -4361,36 +4361,6 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u | |||
4361 | #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0) | 4361 | #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0) |
4362 | #define cciss_noop(p) cciss_message(p, 3, 0) | 4362 | #define cciss_noop(p) cciss_message(p, 3, 0) |
4363 | 4363 | ||
4364 | static __devinit int cciss_reset_msi(struct pci_dev *pdev) | ||
4365 | { | ||
4366 | /* the #defines are stolen from drivers/pci/msi.h. */ | ||
4367 | #define msi_control_reg(base) (base + PCI_MSI_FLAGS) | ||
4368 | #define PCI_MSIX_FLAGS_ENABLE (1 << 15) | ||
4369 | |||
4370 | int pos; | ||
4371 | u16 control = 0; | ||
4372 | |||
4373 | pos = pci_find_capability(pdev, PCI_CAP_ID_MSI); | ||
4374 | if (pos) { | ||
4375 | pci_read_config_word(pdev, msi_control_reg(pos), &control); | ||
4376 | if (control & PCI_MSI_FLAGS_ENABLE) { | ||
4377 | dev_info(&pdev->dev, "resetting MSI\n"); | ||
4378 | pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE); | ||
4379 | } | ||
4380 | } | ||
4381 | |||
4382 | pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); | ||
4383 | if (pos) { | ||
4384 | pci_read_config_word(pdev, msi_control_reg(pos), &control); | ||
4385 | if (control & PCI_MSIX_FLAGS_ENABLE) { | ||
4386 | dev_info(&pdev->dev, "resetting MSI-X\n"); | ||
4387 | pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE); | ||
4388 | } | ||
4389 | } | ||
4390 | |||
4391 | return 0; | ||
4392 | } | ||
4393 | |||
4394 | static int cciss_controller_hard_reset(struct pci_dev *pdev, | 4364 | static int cciss_controller_hard_reset(struct pci_dev *pdev, |
4395 | void * __iomem vaddr, bool use_doorbell) | 4365 | void * __iomem vaddr, bool use_doorbell) |
4396 | { | 4366 | { |
@@ -4445,17 +4415,17 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev, | |||
4445 | * states or using the doorbell register. */ | 4415 | * states or using the doorbell register. */ |
4446 | static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | 4416 | static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) |
4447 | { | 4417 | { |
4448 | u16 saved_config_space[32]; | ||
4449 | u64 cfg_offset; | 4418 | u64 cfg_offset; |
4450 | u32 cfg_base_addr; | 4419 | u32 cfg_base_addr; |
4451 | u64 cfg_base_addr_index; | 4420 | u64 cfg_base_addr_index; |
4452 | void __iomem *vaddr; | 4421 | void __iomem *vaddr; |
4453 | unsigned long paddr; | 4422 | unsigned long paddr; |
4454 | u32 misc_fw_support, active_transport; | 4423 | u32 misc_fw_support, active_transport; |
4455 | int rc, i; | 4424 | int rc; |
4456 | CfgTable_struct __iomem *cfgtable; | 4425 | CfgTable_struct __iomem *cfgtable; |
4457 | bool use_doorbell; | 4426 | bool use_doorbell; |
4458 | u32 board_id; | 4427 | u32 board_id; |
4428 | u16 command_register; | ||
4459 | 4429 | ||
4460 | /* For controllers as old a the p600, this is very nearly | 4430 | /* For controllers as old a the p600, this is very nearly |
4461 | * the same thing as | 4431 | * the same thing as |
@@ -4465,14 +4435,6 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4465 | * pci_set_power_state(pci_dev, PCI_D0); | 4435 | * pci_set_power_state(pci_dev, PCI_D0); |
4466 | * pci_restore_state(pci_dev); | 4436 | * pci_restore_state(pci_dev); |
4467 | * | 4437 | * |
4468 | * but we can't use these nice canned kernel routines on | ||
4469 | * kexec, because they also check the MSI/MSI-X state in PCI | ||
4470 | * configuration space and do the wrong thing when it is | ||
4471 | * set/cleared. Also, the pci_save/restore_state functions | ||
4472 | * violate the ordering requirements for restoring the | ||
4473 | * configuration space from the CCISS document (see the | ||
4474 | * comment below). So we roll our own .... | ||
4475 | * | ||
4476 | * For controllers newer than the P600, the pci power state | 4438 | * For controllers newer than the P600, the pci power state |
4477 | * method of resetting doesn't work so we have another way | 4439 | * method of resetting doesn't work so we have another way |
4478 | * using the doorbell register. | 4440 | * using the doorbell register. |
@@ -4491,8 +4453,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4491 | return -ENODEV; | 4453 | return -ENODEV; |
4492 | } | 4454 | } |
4493 | 4455 | ||
4494 | for (i = 0; i < 32; i++) | 4456 | /* Save the PCI command register */ |
4495 | pci_read_config_word(pdev, 2*i, &saved_config_space[i]); | 4457 | pci_read_config_word(pdev, 4, &command_register); |
4458 | /* Turn the board off. This is so that later pci_restore_state() | ||
4459 | * won't turn the board on before the rest of config space is ready. | ||
4460 | */ | ||
4461 | pci_disable_device(pdev); | ||
4462 | pci_save_state(pdev); | ||
4496 | 4463 | ||
4497 | /* find the first memory BAR, so we can find the cfg table */ | 4464 | /* find the first memory BAR, so we can find the cfg table */ |
4498 | rc = cciss_pci_find_memory_BAR(pdev, &paddr); | 4465 | rc = cciss_pci_find_memory_BAR(pdev, &paddr); |
@@ -4527,21 +4494,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4527 | rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell); | 4494 | rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell); |
4528 | if (rc) | 4495 | if (rc) |
4529 | goto unmap_cfgtable; | 4496 | goto unmap_cfgtable; |
4530 | 4497 | pci_restore_state(pdev); | |
4531 | /* Restore the PCI configuration space. The Open CISS | 4498 | rc = pci_enable_device(pdev); |
4532 | * Specification says, "Restore the PCI Configuration | 4499 | if (rc) { |
4533 | * Registers, offsets 00h through 60h. It is important to | 4500 | dev_warn(&pdev->dev, "failed to enable device.\n"); |
4534 | * restore the command register, 16-bits at offset 04h, | 4501 | goto unmap_cfgtable; |
4535 | * last. Do not restore the configuration status register, | ||
4536 | * 16-bits at offset 06h." Note that the offset is 2*i. | ||
4537 | */ | ||
4538 | for (i = 0; i < 32; i++) { | ||
4539 | if (i == 2 || i == 3) | ||
4540 | continue; | ||
4541 | pci_write_config_word(pdev, 2*i, saved_config_space[i]); | ||
4542 | } | 4502 | } |
4543 | wmb(); | 4503 | pci_write_config_word(pdev, 4, command_register); |
4544 | pci_write_config_word(pdev, 4, saved_config_space[2]); | ||
4545 | 4504 | ||
4546 | /* Some devices (notably the HP Smart Array 5i Controller) | 4505 | /* Some devices (notably the HP Smart Array 5i Controller) |
4547 | need a little pause here */ | 4506 | need a little pause here */ |
@@ -4601,8 +4560,6 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev) | |||
4601 | return 0; /* just try to do the kdump anyhow. */ | 4560 | return 0; /* just try to do the kdump anyhow. */ |
4602 | if (rc) | 4561 | if (rc) |
4603 | return -ENODEV; | 4562 | return -ENODEV; |
4604 | if (cciss_reset_msi(pdev)) | ||
4605 | return -ENODEV; | ||
4606 | 4563 | ||
4607 | /* Now try to get the controller to respond to a no-op */ | 4564 | /* Now try to get the controller to respond to a no-op */ |
4608 | for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) { | 4565 | for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) { |