aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStephen M. Cameron <scameron@beardog.cce.hp.com>2010-07-19 14:46:22 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-07 12:52:30 -0400
commita6528d017234b483283274fbdd360f3541befe19 (patch)
treec273b7e7752a4f846d4e8cba2bf6cedd890dab23 /drivers
parent83123cb11b5a5205233c59357da2c8d9a8dc9d24 (diff)
cciss: fix hard reset code.
cciss: Fix hard reset code. Smart Array controllers newer than the P600 do not honor the PCI power state method of resetting the controllers. Instead, in these cases we can get them to reset via the "doorbell" register. This escaped notice until we began using "performant" mode because the fact that the controllers did not reset did not normally impede subsequent operation, and so things generally appeared to "work". Once the performant mode code was added, if the controller does not reset, it remains in performant mode. The code immediately after the reset presumes the controller is in "simple" mode (which previously, it had remained in simple mode the whole time). If the controller remains in performant mode any code which presumes it is in simple mode will not work. So the reset needs to be fixed. Unfortunately there are some controllers which cannot be reset by either method. (eg. p800). We detect these cases by noticing that the controller seems to remain in performant mode even after a reset has been attempted. In those cases we ignore the controller, as any commands outstanding on it will result in stale completions. To sum up, we try to do a better job of resetting the controller if "reset_devices" is set, and if it doesn't work, we ignore that controller. Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/cciss.c200
-rw-r--r--drivers/block/cciss_cmd.h4
2 files changed, 152 insertions, 52 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index f49dcd734d1..b3060eced55 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -216,6 +216,12 @@ static void cciss_device_release(struct device *dev);
216static void cciss_free_gendisk(ctlr_info_t *h, int drv_index); 216static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
217static void cciss_free_drive_info(ctlr_info_t *h, int drv_index); 217static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
218static inline u32 next_command(ctlr_info_t *h); 218static inline u32 next_command(ctlr_info_t *h);
219static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
220 void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
221 u64 *cfg_offset);
222static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
223 unsigned long *memory_bar);
224
219 225
220/* performant mode helper functions */ 226/* performant mode helper functions */
221static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, 227static void calc_bucket_map(int *bucket, int num_buckets, int nsgs,
@@ -4413,68 +4419,130 @@ static __devinit int cciss_reset_msi(struct pci_dev *pdev)
4413 return 0; 4419 return 0;
4414} 4420}
4415 4421
4416/* This does a hard reset of the controller using PCI power management 4422static int cciss_controller_hard_reset(struct pci_dev *pdev,
4417 * states. */ 4423 void * __iomem vaddr, bool use_doorbell)
4418static __devinit int cciss_hard_reset_controller(struct pci_dev *pdev)
4419{ 4424{
4420 u16 pmcsr, saved_config_space[32]; 4425 u16 pmcsr;
4421 int i, pos; 4426 int pos;
4422 4427
4423 printk(KERN_INFO "cciss: using PCI PM to reset controller\n"); 4428 if (use_doorbell) {
4429 /* For everything after the P600, the PCI power state method
4430 * of resetting the controller doesn't work, so we have this
4431 * other way using the doorbell register.
4432 */
4433 dev_info(&pdev->dev, "using doorbell to reset controller\n");
4434 writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
4435 msleep(1000);
4436 } else { /* Try to do it the PCI power state way */
4437
4438 /* Quoting from the Open CISS Specification: "The Power
4439 * Management Control/Status Register (CSR) controls the power
4440 * state of the device. The normal operating state is D0,
4441 * CSR=00h. The software off state is D3, CSR=03h. To reset
4442 * the controller, place the interface device in D3 then to D0,
4443 * this causes a secondary PCI reset which will reset the
4444 * controller." */
4445
4446 pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
4447 if (pos == 0) {
4448 dev_err(&pdev->dev,
4449 "cciss_controller_hard_reset: "
4450 "PCI PM not supported\n");
4451 return -ENODEV;
4452 }
4453 dev_info(&pdev->dev, "using PCI PM to reset controller\n");
4454 /* enter the D3hot power management state */
4455 pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
4456 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
4457 pmcsr |= PCI_D3hot;
4458 pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
4424 4459
4425 /* This is very nearly the same thing as 4460 msleep(500);
4426 4461
4427 pci_save_state(pci_dev); 4462 /* enter the D0 power management state */
4428 pci_set_power_state(pci_dev, PCI_D3hot); 4463 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
4429 pci_set_power_state(pci_dev, PCI_D0); 4464 pmcsr |= PCI_D0;
4430 pci_restore_state(pci_dev); 4465 pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
4431 4466
4432 but we can't use these nice canned kernel routines on 4467 msleep(500);
4433 kexec, because they also check the MSI/MSI-X state in PCI 4468 }
4434 configuration space and do the wrong thing when it is 4469 return 0;
4435 set/cleared. Also, the pci_save/restore_state functions 4470}
4436 violate the ordering requirements for restoring the 4471
4437 configuration space from the CCISS document (see the 4472/* This does a hard reset of the controller using PCI power management
4438 comment below). So we roll our own .... */ 4473 * states or using the doorbell register. */
4474static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
4475{
4476 u16 saved_config_space[32];
4477 u64 cfg_offset;
4478 u32 cfg_base_addr;
4479 u64 cfg_base_addr_index;
4480 void __iomem *vaddr;
4481 unsigned long paddr;
4482 u32 misc_fw_support, active_transport;
4483 int rc, i;
4484 CfgTable_struct __iomem *cfgtable;
4485 bool use_doorbell;
4486
4487 /* For controllers as old a the p600, this is very nearly
4488 * the same thing as
4489 *
4490 * pci_save_state(pci_dev);
4491 * pci_set_power_state(pci_dev, PCI_D3hot);
4492 * pci_set_power_state(pci_dev, PCI_D0);
4493 * pci_restore_state(pci_dev);
4494 *
4495 * but we can't use these nice canned kernel routines on
4496 * kexec, because they also check the MSI/MSI-X state in PCI
4497 * configuration space and do the wrong thing when it is
4498 * set/cleared. Also, the pci_save/restore_state functions
4499 * violate the ordering requirements for restoring the
4500 * configuration space from the CCISS document (see the
4501 * comment below). So we roll our own ....
4502 *
4503 * For controllers newer than the P600, the pci power state
4504 * method of resetting doesn't work so we have another way
4505 * using the doorbell register.
4506 */
4439 4507
4440 for (i = 0; i < 32; i++) 4508 for (i = 0; i < 32; i++)
4441 pci_read_config_word(pdev, 2*i, &saved_config_space[i]); 4509 pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
4442 4510
4443 pos = pci_find_capability(pdev, PCI_CAP_ID_PM); 4511 /* find the first memory BAR, so we can find the cfg table */
4444 if (pos == 0) { 4512 rc = cciss_pci_find_memory_BAR(pdev, &paddr);
4445 printk(KERN_ERR "cciss_reset_controller: PCI PM not supported\n"); 4513 if (rc)
4446 return -ENODEV; 4514 return rc;
4447 } 4515 vaddr = remap_pci_mem(paddr, 0x250);
4448 4516 if (!vaddr)
4449 /* Quoting from the Open CISS Specification: "The Power 4517 return -ENOMEM;
4450 * Management Control/Status Register (CSR) controls the power
4451 * state of the device. The normal operating state is D0,
4452 * CSR=00h. The software off state is D3, CSR=03h. To reset
4453 * the controller, place the interface device in D3 then to
4454 * D0, this causes a secondary PCI reset which will reset the
4455 * controller." */
4456
4457 /* enter the D3hot power management state */
4458 pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
4459 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
4460 pmcsr |= PCI_D3hot;
4461 pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
4462 4518
4463 schedule_timeout_uninterruptible(HZ >> 1); 4519 /* find cfgtable in order to check if reset via doorbell is supported */
4520 rc = cciss_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
4521 &cfg_base_addr_index, &cfg_offset);
4522 if (rc)
4523 goto unmap_vaddr;
4524 cfgtable = remap_pci_mem(pci_resource_start(pdev,
4525 cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
4526 if (!cfgtable) {
4527 rc = -ENOMEM;
4528 goto unmap_vaddr;
4529 }
4464 4530
4465 /* enter the D0 power management state */ 4531 /* If reset via doorbell register is supported, use that. */
4466 pmcsr &= ~PCI_PM_CTRL_STATE_MASK; 4532 misc_fw_support = readl(&cfgtable->misc_fw_support);
4467 pmcsr |= PCI_D0; 4533 use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
4468 pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
4469 4534
4470 schedule_timeout_uninterruptible(HZ >> 1); 4535 rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
4536 if (rc)
4537 goto unmap_cfgtable;
4471 4538
4472 /* Restore the PCI configuration space. The Open CISS 4539 /* Restore the PCI configuration space. The Open CISS
4473 * Specification says, "Restore the PCI Configuration 4540 * Specification says, "Restore the PCI Configuration
4474 * Registers, offsets 00h through 60h. It is important to 4541 * Registers, offsets 00h through 60h. It is important to
4475 * restore the command register, 16-bits at offset 04h, 4542 * restore the command register, 16-bits at offset 04h,
4476 * last. Do not restore the configuration status register, 4543 * last. Do not restore the configuration status register,
4477 * 16-bits at offset 06h." Note that the offset is 2*i. */ 4544 * 16-bits at offset 06h." Note that the offset is 2*i.
4545 */
4478 for (i = 0; i < 32; i++) { 4546 for (i = 0; i < 32; i++) {
4479 if (i == 2 || i == 3) 4547 if (i == 2 || i == 3)
4480 continue; 4548 continue;
@@ -4483,23 +4551,51 @@ static __devinit int cciss_hard_reset_controller(struct pci_dev *pdev)
4483 wmb(); 4551 wmb();
4484 pci_write_config_word(pdev, 4, saved_config_space[2]); 4552 pci_write_config_word(pdev, 4, saved_config_space[2]);
4485 4553
4486 return 0; 4554 /* Some devices (notably the HP Smart Array 5i Controller)
4555 need a little pause here */
4556 msleep(CCISS_POST_RESET_PAUSE_MSECS);
4557
4558 /* Controller should be in simple mode at this point. If it's not,
4559 * It means we're on one of those controllers which doesn't support
4560 * the doorbell reset method and on which the PCI power management reset
4561 * method doesn't work (P800, for example.)
4562 * In those cases, don't try to proceed, as it generally doesn't work.
4563 */
4564 active_transport = readl(&cfgtable->TransportActive);
4565 if (active_transport & PERFORMANT_MODE) {
4566 dev_warn(&pdev->dev, "Unable to successfully reset controller,"
4567 " Ignoring controller.\n");
4568 rc = -ENODEV;
4569 }
4570
4571unmap_cfgtable:
4572 iounmap(cfgtable);
4573
4574unmap_vaddr:
4575 iounmap(vaddr);
4576 return rc;
4487} 4577}
4488 4578
4489static __devinit int cciss_init_reset_devices(struct pci_dev *pdev) 4579static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
4490{ 4580{
4491 int i; 4581 int rc, i;
4492 4582
4493 if (!reset_devices) 4583 if (!reset_devices)
4494 return 0; 4584 return 0;
4495 4585
4496 /* Reset the controller with a PCI power-cycle */ 4586 /* Reset the controller with a PCI power-cycle or via doorbell */
4497 if (cciss_hard_reset_controller(pdev) || cciss_reset_msi(pdev)) 4587 rc = cciss_kdump_hard_reset_controller(pdev);
4498 return -ENODEV;
4499 4588
4500 /* Some devices (notably the HP Smart Array 5i Controller) 4589 /* -ENOTSUPP here means we cannot reset the controller
4501 need a little pause here */ 4590 * but it's already (and still) up and running in
4502 msleep(CCISS_POST_RESET_PAUSE_MSECS); 4591 * "performant mode".
4592 */
4593 if (rc == -ENOTSUPP)
4594 return 0; /* just try to do the kdump anyhow. */
4595 if (rc)
4596 return -ENODEV;
4597 if (cciss_reset_msi(pdev))
4598 return -ENODEV;
4503 4599
4504 /* Now try to get the controller to respond to a no-op */ 4600 /* Now try to get the controller to respond to a no-op */
4505 for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) { 4601 for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index 936b9666da6..eb060f1b00b 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -52,6 +52,7 @@
52/* Configuration Table */ 52/* Configuration Table */
53#define CFGTBL_ChangeReq 0x00000001l 53#define CFGTBL_ChangeReq 0x00000001l
54#define CFGTBL_AccCmds 0x00000001l 54#define CFGTBL_AccCmds 0x00000001l
55#define DOORBELL_CTLR_RESET 0x00000004l
55 56
56#define CFGTBL_Trans_Simple 0x00000002l 57#define CFGTBL_Trans_Simple 0x00000002l
57#define CFGTBL_Trans_Performant 0x00000004l 58#define CFGTBL_Trans_Performant 0x00000004l
@@ -230,6 +231,9 @@ typedef struct _CfgTable_struct {
230 DWORD MaxPhysicalDrives; 231 DWORD MaxPhysicalDrives;
231 DWORD MaxPhysicalDrivesPerLogicalUnit; 232 DWORD MaxPhysicalDrivesPerLogicalUnit;
232 DWORD MaxPerformantModeCommands; 233 DWORD MaxPerformantModeCommands;
234 u8 reserved[0x78 - 0x58];
235 u32 misc_fw_support; /* offset 0x78 */
236#define MISC_FW_DOORBELL_RESET (0x02)
233} CfgTable_struct; 237} CfgTable_struct;
234 238
235struct TransTable_struct { 239struct TransTable_struct {