diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 131 |
1 files changed, 61 insertions, 70 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 2cc4dda46279..a67d0a611a8a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -113,6 +113,8 @@ static struct board_type products[] = { | |||
113 | {0x409D0E11, "Smart Array 6400 EM", &SA5_access}, | 113 | {0x409D0E11, "Smart Array 6400 EM", &SA5_access}, |
114 | {0x40910E11, "Smart Array 6i", &SA5_access}, | 114 | {0x40910E11, "Smart Array 6i", &SA5_access}, |
115 | {0x3225103C, "Smart Array P600", &SA5_access}, | 115 | {0x3225103C, "Smart Array P600", &SA5_access}, |
116 | {0x3223103C, "Smart Array P800", &SA5_access}, | ||
117 | {0x3234103C, "Smart Array P400", &SA5_access}, | ||
116 | {0x3235103C, "Smart Array P400i", &SA5_access}, | 118 | {0x3235103C, "Smart Array P400i", &SA5_access}, |
117 | {0x3211103C, "Smart Array E200i", &SA5_access}, | 119 | {0x3211103C, "Smart Array E200i", &SA5_access}, |
118 | {0x3212103C, "Smart Array E200", &SA5_access}, | 120 | {0x3212103C, "Smart Array E200", &SA5_access}, |
@@ -3753,7 +3755,7 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h) | |||
3753 | for (i = 0; i < MAX_CONFIG_WAIT; i++) { | 3755 | for (i = 0; i < MAX_CONFIG_WAIT; i++) { |
3754 | if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) | 3756 | if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) |
3755 | break; | 3757 | break; |
3756 | msleep(10); | 3758 | usleep_range(10000, 20000); |
3757 | } | 3759 | } |
3758 | } | 3760 | } |
3759 | 3761 | ||
@@ -3937,10 +3939,9 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id) | |||
3937 | *board_id = ((subsystem_device_id << 16) & 0xffff0000) | | 3939 | *board_id = ((subsystem_device_id << 16) & 0xffff0000) | |
3938 | subsystem_vendor_id; | 3940 | subsystem_vendor_id; |
3939 | 3941 | ||
3940 | for (i = 0; i < ARRAY_SIZE(products); i++) { | 3942 | for (i = 0; i < ARRAY_SIZE(products); i++) |
3941 | if (*board_id == products[i].board_id) | 3943 | if (*board_id == products[i].board_id) |
3942 | return i; | 3944 | return i; |
3943 | } | ||
3944 | dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n", | 3945 | dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n", |
3945 | *board_id); | 3946 | *board_id); |
3946 | return -ENODEV; | 3947 | return -ENODEV; |
@@ -3971,18 +3972,31 @@ static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, | |||
3971 | return -ENODEV; | 3972 | return -ENODEV; |
3972 | } | 3973 | } |
3973 | 3974 | ||
3974 | static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h) | 3975 | static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev, |
3976 | void __iomem *vaddr, int wait_for_ready) | ||
3977 | #define BOARD_READY 1 | ||
3978 | #define BOARD_NOT_READY 0 | ||
3975 | { | 3979 | { |
3976 | int i; | 3980 | int i, iterations; |
3977 | u32 scratchpad; | 3981 | u32 scratchpad; |
3978 | 3982 | ||
3979 | for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) { | 3983 | if (wait_for_ready) |
3980 | scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); | 3984 | iterations = CCISS_BOARD_READY_ITERATIONS; |
3981 | if (scratchpad == CCISS_FIRMWARE_READY) | 3985 | else |
3982 | return 0; | 3986 | iterations = CCISS_BOARD_NOT_READY_ITERATIONS; |
3987 | |||
3988 | for (i = 0; i < iterations; i++) { | ||
3989 | scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET); | ||
3990 | if (wait_for_ready) { | ||
3991 | if (scratchpad == CCISS_FIRMWARE_READY) | ||
3992 | return 0; | ||
3993 | } else { | ||
3994 | if (scratchpad != CCISS_FIRMWARE_READY) | ||
3995 | return 0; | ||
3996 | } | ||
3983 | msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS); | 3997 | msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS); |
3984 | } | 3998 | } |
3985 | dev_warn(&h->pdev->dev, "board not ready, timed out.\n"); | 3999 | dev_warn(&pdev->dev, "board not ready, timed out.\n"); |
3986 | return -ENODEV; | 4000 | return -ENODEV; |
3987 | } | 4001 | } |
3988 | 4002 | ||
@@ -4031,6 +4045,11 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h) | |||
4031 | static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h) | 4045 | static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h) |
4032 | { | 4046 | { |
4033 | h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); | 4047 | h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); |
4048 | |||
4049 | /* Limit commands in memory limited kdump scenario. */ | ||
4050 | if (reset_devices && h->max_commands > 32) | ||
4051 | h->max_commands = 32; | ||
4052 | |||
4034 | if (h->max_commands < 16) { | 4053 | if (h->max_commands < 16) { |
4035 | dev_warn(&h->pdev->dev, "Controller reports " | 4054 | dev_warn(&h->pdev->dev, "Controller reports " |
4036 | "max supported commands of %d, an obvious lie. " | 4055 | "max supported commands of %d, an obvious lie. " |
@@ -4148,7 +4167,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *h) | |||
4148 | err = -ENOMEM; | 4167 | err = -ENOMEM; |
4149 | goto err_out_free_res; | 4168 | goto err_out_free_res; |
4150 | } | 4169 | } |
4151 | err = cciss_wait_for_board_ready(h); | 4170 | err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); |
4152 | if (err) | 4171 | if (err) |
4153 | goto err_out_free_res; | 4172 | goto err_out_free_res; |
4154 | err = cciss_find_cfgtables(h); | 4173 | err = cciss_find_cfgtables(h); |
@@ -4313,36 +4332,6 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u | |||
4313 | #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0) | 4332 | #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0) |
4314 | #define cciss_noop(p) cciss_message(p, 3, 0) | 4333 | #define cciss_noop(p) cciss_message(p, 3, 0) |
4315 | 4334 | ||
4316 | static __devinit int cciss_reset_msi(struct pci_dev *pdev) | ||
4317 | { | ||
4318 | /* the #defines are stolen from drivers/pci/msi.h. */ | ||
4319 | #define msi_control_reg(base) (base + PCI_MSI_FLAGS) | ||
4320 | #define PCI_MSIX_FLAGS_ENABLE (1 << 15) | ||
4321 | |||
4322 | int pos; | ||
4323 | u16 control = 0; | ||
4324 | |||
4325 | pos = pci_find_capability(pdev, PCI_CAP_ID_MSI); | ||
4326 | if (pos) { | ||
4327 | pci_read_config_word(pdev, msi_control_reg(pos), &control); | ||
4328 | if (control & PCI_MSI_FLAGS_ENABLE) { | ||
4329 | dev_info(&pdev->dev, "resetting MSI\n"); | ||
4330 | pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE); | ||
4331 | } | ||
4332 | } | ||
4333 | |||
4334 | pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); | ||
4335 | if (pos) { | ||
4336 | pci_read_config_word(pdev, msi_control_reg(pos), &control); | ||
4337 | if (control & PCI_MSIX_FLAGS_ENABLE) { | ||
4338 | dev_info(&pdev->dev, "resetting MSI-X\n"); | ||
4339 | pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE); | ||
4340 | } | ||
4341 | } | ||
4342 | |||
4343 | return 0; | ||
4344 | } | ||
4345 | |||
4346 | static int cciss_controller_hard_reset(struct pci_dev *pdev, | 4335 | static int cciss_controller_hard_reset(struct pci_dev *pdev, |
4347 | void * __iomem vaddr, bool use_doorbell) | 4336 | void * __iomem vaddr, bool use_doorbell) |
4348 | { | 4337 | { |
@@ -4397,17 +4386,17 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev, | |||
4397 | * states or using the doorbell register. */ | 4386 | * states or using the doorbell register. */ |
4398 | static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | 4387 | static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) |
4399 | { | 4388 | { |
4400 | u16 saved_config_space[32]; | ||
4401 | u64 cfg_offset; | 4389 | u64 cfg_offset; |
4402 | u32 cfg_base_addr; | 4390 | u32 cfg_base_addr; |
4403 | u64 cfg_base_addr_index; | 4391 | u64 cfg_base_addr_index; |
4404 | void __iomem *vaddr; | 4392 | void __iomem *vaddr; |
4405 | unsigned long paddr; | 4393 | unsigned long paddr; |
4406 | u32 misc_fw_support, active_transport; | 4394 | u32 misc_fw_support, active_transport; |
4407 | int rc, i; | 4395 | int rc; |
4408 | CfgTable_struct __iomem *cfgtable; | 4396 | CfgTable_struct __iomem *cfgtable; |
4409 | bool use_doorbell; | 4397 | bool use_doorbell; |
4410 | u32 board_id; | 4398 | u32 board_id; |
4399 | u16 command_register; | ||
4411 | 4400 | ||
4412 | /* For controllers as old a the p600, this is very nearly | 4401 | /* For controllers as old a the p600, this is very nearly |
4413 | * the same thing as | 4402 | * the same thing as |
@@ -4417,14 +4406,6 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4417 | * pci_set_power_state(pci_dev, PCI_D0); | 4406 | * pci_set_power_state(pci_dev, PCI_D0); |
4418 | * pci_restore_state(pci_dev); | 4407 | * pci_restore_state(pci_dev); |
4419 | * | 4408 | * |
4420 | * but we can't use these nice canned kernel routines on | ||
4421 | * kexec, because they also check the MSI/MSI-X state in PCI | ||
4422 | * configuration space and do the wrong thing when it is | ||
4423 | * set/cleared. Also, the pci_save/restore_state functions | ||
4424 | * violate the ordering requirements for restoring the | ||
4425 | * configuration space from the CCISS document (see the | ||
4426 | * comment below). So we roll our own .... | ||
4427 | * | ||
4428 | * For controllers newer than the P600, the pci power state | 4409 | * For controllers newer than the P600, the pci power state |
4429 | * method of resetting doesn't work so we have another way | 4410 | * method of resetting doesn't work so we have another way |
4430 | * using the doorbell register. | 4411 | * using the doorbell register. |
@@ -4443,8 +4424,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4443 | return -ENODEV; | 4424 | return -ENODEV; |
4444 | } | 4425 | } |
4445 | 4426 | ||
4446 | for (i = 0; i < 32; i++) | 4427 | /* Save the PCI command register */ |
4447 | pci_read_config_word(pdev, 2*i, &saved_config_space[i]); | 4428 | pci_read_config_word(pdev, 4, &command_register); |
4429 | /* Turn the board off. This is so that later pci_restore_state() | ||
4430 | * won't turn the board on before the rest of config space is ready. | ||
4431 | */ | ||
4432 | pci_disable_device(pdev); | ||
4433 | pci_save_state(pdev); | ||
4448 | 4434 | ||
4449 | /* find the first memory BAR, so we can find the cfg table */ | 4435 | /* find the first memory BAR, so we can find the cfg table */ |
4450 | rc = cciss_pci_find_memory_BAR(pdev, &paddr); | 4436 | rc = cciss_pci_find_memory_BAR(pdev, &paddr); |
@@ -4479,26 +4465,32 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4479 | rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell); | 4465 | rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell); |
4480 | if (rc) | 4466 | if (rc) |
4481 | goto unmap_cfgtable; | 4467 | goto unmap_cfgtable; |
4482 | 4468 | pci_restore_state(pdev); | |
4483 | /* Restore the PCI configuration space. The Open CISS | 4469 | rc = pci_enable_device(pdev); |
4484 | * Specification says, "Restore the PCI Configuration | 4470 | if (rc) { |
4485 | * Registers, offsets 00h through 60h. It is important to | 4471 | dev_warn(&pdev->dev, "failed to enable device.\n"); |
4486 | * restore the command register, 16-bits at offset 04h, | 4472 | goto unmap_cfgtable; |
4487 | * last. Do not restore the configuration status register, | ||
4488 | * 16-bits at offset 06h." Note that the offset is 2*i. | ||
4489 | */ | ||
4490 | for (i = 0; i < 32; i++) { | ||
4491 | if (i == 2 || i == 3) | ||
4492 | continue; | ||
4493 | pci_write_config_word(pdev, 2*i, saved_config_space[i]); | ||
4494 | } | 4473 | } |
4495 | wmb(); | 4474 | pci_write_config_word(pdev, 4, command_register); |
4496 | pci_write_config_word(pdev, 4, saved_config_space[2]); | ||
4497 | 4475 | ||
4498 | /* Some devices (notably the HP Smart Array 5i Controller) | 4476 | /* Some devices (notably the HP Smart Array 5i Controller) |
4499 | need a little pause here */ | 4477 | need a little pause here */ |
4500 | msleep(CCISS_POST_RESET_PAUSE_MSECS); | 4478 | msleep(CCISS_POST_RESET_PAUSE_MSECS); |
4501 | 4479 | ||
4480 | /* Wait for board to become not ready, then ready. */ | ||
4481 | dev_info(&pdev->dev, "Waiting for board to become ready.\n"); | ||
4482 | rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY); | ||
4483 | if (rc) /* Don't bail, might be E500, etc. which can't be reset */ | ||
4484 | dev_warn(&pdev->dev, | ||
4485 | "failed waiting for board to become not ready\n"); | ||
4486 | rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY); | ||
4487 | if (rc) { | ||
4488 | dev_warn(&pdev->dev, | ||
4489 | "failed waiting for board to become ready\n"); | ||
4490 | goto unmap_cfgtable; | ||
4491 | } | ||
4492 | dev_info(&pdev->dev, "board ready.\n"); | ||
4493 | |||
4502 | /* Controller should be in simple mode at this point. If it's not, | 4494 | /* Controller should be in simple mode at this point. If it's not, |
4503 | * It means we're on one of those controllers which doesn't support | 4495 | * It means we're on one of those controllers which doesn't support |
4504 | * the doorbell reset method and on which the PCI power management reset | 4496 | * the doorbell reset method and on which the PCI power management reset |
@@ -4539,8 +4531,6 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev) | |||
4539 | return 0; /* just try to do the kdump anyhow. */ | 4531 | return 0; /* just try to do the kdump anyhow. */ |
4540 | if (rc) | 4532 | if (rc) |
4541 | return -ENODEV; | 4533 | return -ENODEV; |
4542 | if (cciss_reset_msi(pdev)) | ||
4543 | return -ENODEV; | ||
4544 | 4534 | ||
4545 | /* Now try to get the controller to respond to a no-op */ | 4535 | /* Now try to get the controller to respond to a no-op */ |
4546 | for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) { | 4536 | for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) { |
@@ -4936,7 +4926,8 @@ static void __exit cciss_cleanup(void) | |||
4936 | } | 4926 | } |
4937 | } | 4927 | } |
4938 | kthread_stop(cciss_scan_thread); | 4928 | kthread_stop(cciss_scan_thread); |
4939 | remove_proc_entry("driver/cciss", NULL); | 4929 | if (proc_cciss) |
4930 | remove_proc_entry("driver/cciss", NULL); | ||
4940 | bus_unregister(&cciss_bus_type); | 4931 | bus_unregister(&cciss_bus_type); |
4941 | } | 4932 | } |
4942 | 4933 | ||