aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/cciss.c
diff options
context:
space:
mode:
authorStephen M. Cameron <scameron@beardog.cce.hp.com>2010-10-22 15:21:12 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-10-23 12:45:07 -0400
commitf442e64b93e16dba6bf9ab7e8dc5a90f6bcd8a85 (patch)
treec8418e1e6c7291232bbb531817740a86e582920a /drivers/block/cciss.c
parentafa842fa641e11a025725883b04d1e144e6bad39 (diff)
cciss: Use kernel provided PCI state save and restore functions
and use the doorbell reset method if available (which doesn't lock up the controller if you properly save and restore all the PCI registers that you're supposed to.) Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r--drivers/block/cciss.c73
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
4364static __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
4394static int cciss_controller_hard_reset(struct pci_dev *pdev, 4364static 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. */
4446static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) 4416static __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++) {