aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
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 {