diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/cciss.c | 82 | ||||
-rw-r--r-- | drivers/block/cciss_cmd.h | 1 |
2 files changed, 73 insertions, 10 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 9bf13988f1a2..ed6aa83d86dd 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -194,6 +194,8 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev, | |||
194 | static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, | 194 | static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, |
195 | unsigned long *memory_bar); | 195 | unsigned long *memory_bar); |
196 | static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag); | 196 | static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag); |
197 | static __devinit int write_driver_ver_to_cfgtable( | ||
198 | CfgTable_struct __iomem *cfgtable); | ||
197 | 199 | ||
198 | /* performant mode helper functions */ | 200 | /* performant mode helper functions */ |
199 | static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, | 201 | static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, |
@@ -4078,6 +4080,9 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h) | |||
4078 | cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable)); | 4080 | cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable)); |
4079 | if (!h->cfgtable) | 4081 | if (!h->cfgtable) |
4080 | return -ENOMEM; | 4082 | return -ENOMEM; |
4083 | rc = write_driver_ver_to_cfgtable(h->cfgtable); | ||
4084 | if (rc) | ||
4085 | return rc; | ||
4081 | /* Find performant mode table. */ | 4086 | /* Find performant mode table. */ |
4082 | trans_offset = readl(&h->cfgtable->TransMethodOffset); | 4087 | trans_offset = readl(&h->cfgtable->TransMethodOffset); |
4083 | h->transtable = remap_pci_mem(pci_resource_start(h->pdev, | 4088 | h->transtable = remap_pci_mem(pci_resource_start(h->pdev, |
@@ -4428,6 +4433,60 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev, | |||
4428 | return 0; | 4433 | return 0; |
4429 | } | 4434 | } |
4430 | 4435 | ||
4436 | static __devinit void init_driver_version(char *driver_version, int len) | ||
4437 | { | ||
4438 | memset(driver_version, 0, len); | ||
4439 | strncpy(driver_version, "cciss " DRIVER_NAME, len - 1); | ||
4440 | } | ||
4441 | |||
4442 | static __devinit int write_driver_ver_to_cfgtable( | ||
4443 | CfgTable_struct __iomem *cfgtable) | ||
4444 | { | ||
4445 | char *driver_version; | ||
4446 | int i, size = sizeof(cfgtable->driver_version); | ||
4447 | |||
4448 | driver_version = kmalloc(size, GFP_KERNEL); | ||
4449 | if (!driver_version) | ||
4450 | return -ENOMEM; | ||
4451 | |||
4452 | init_driver_version(driver_version, size); | ||
4453 | for (i = 0; i < size; i++) | ||
4454 | writeb(driver_version[i], &cfgtable->driver_version[i]); | ||
4455 | kfree(driver_version); | ||
4456 | return 0; | ||
4457 | } | ||
4458 | |||
4459 | static __devinit void read_driver_ver_from_cfgtable( | ||
4460 | CfgTable_struct __iomem *cfgtable, unsigned char *driver_ver) | ||
4461 | { | ||
4462 | int i; | ||
4463 | |||
4464 | for (i = 0; i < sizeof(cfgtable->driver_version); i++) | ||
4465 | driver_ver[i] = readb(&cfgtable->driver_version[i]); | ||
4466 | } | ||
4467 | |||
4468 | static __devinit int controller_reset_failed( | ||
4469 | CfgTable_struct __iomem *cfgtable) | ||
4470 | { | ||
4471 | |||
4472 | char *driver_ver, *old_driver_ver; | ||
4473 | int rc, size = sizeof(cfgtable->driver_version); | ||
4474 | |||
4475 | old_driver_ver = kmalloc(2 * size, GFP_KERNEL); | ||
4476 | if (!old_driver_ver) | ||
4477 | return -ENOMEM; | ||
4478 | driver_ver = old_driver_ver + size; | ||
4479 | |||
4480 | /* After a reset, the 32 bytes of "driver version" in the cfgtable | ||
4481 | * should have been changed, otherwise we know the reset failed. | ||
4482 | */ | ||
4483 | init_driver_version(old_driver_ver, size); | ||
4484 | read_driver_ver_from_cfgtable(cfgtable, driver_ver); | ||
4485 | rc = !memcmp(driver_ver, old_driver_ver, size); | ||
4486 | kfree(old_driver_ver); | ||
4487 | return rc; | ||
4488 | } | ||
4489 | |||
4431 | /* This does a hard reset of the controller using PCI power management | 4490 | /* This does a hard reset of the controller using PCI power management |
4432 | * states or using the doorbell register. */ | 4491 | * states or using the doorbell register. */ |
4433 | static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | 4492 | static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) |
@@ -4437,7 +4496,7 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4437 | u64 cfg_base_addr_index; | 4496 | u64 cfg_base_addr_index; |
4438 | void __iomem *vaddr; | 4497 | void __iomem *vaddr; |
4439 | unsigned long paddr; | 4498 | unsigned long paddr; |
4440 | u32 misc_fw_support, active_transport; | 4499 | u32 misc_fw_support; |
4441 | int rc; | 4500 | int rc; |
4442 | CfgTable_struct __iomem *cfgtable; | 4501 | CfgTable_struct __iomem *cfgtable; |
4443 | bool use_doorbell; | 4502 | bool use_doorbell; |
@@ -4497,6 +4556,9 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4497 | rc = -ENOMEM; | 4556 | rc = -ENOMEM; |
4498 | goto unmap_vaddr; | 4557 | goto unmap_vaddr; |
4499 | } | 4558 | } |
4559 | rc = write_driver_ver_to_cfgtable(cfgtable); | ||
4560 | if (rc) | ||
4561 | goto unmap_vaddr; | ||
4500 | 4562 | ||
4501 | /* If reset via doorbell register is supported, use that. */ | 4563 | /* If reset via doorbell register is supported, use that. */ |
4502 | misc_fw_support = readl(&cfgtable->misc_fw_support); | 4564 | misc_fw_support = readl(&cfgtable->misc_fw_support); |
@@ -4535,21 +4597,21 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) | |||
4535 | "failed waiting for board to become ready\n"); | 4597 | "failed waiting for board to become ready\n"); |
4536 | goto unmap_cfgtable; | 4598 | goto unmap_cfgtable; |
4537 | } | 4599 | } |
4538 | dev_info(&pdev->dev, "board ready.\n"); | ||
4539 | 4600 | ||
4540 | /* Controller should be in simple mode at this point. If it's not, | 4601 | rc = controller_reset_failed(vaddr); |
4541 | * It means we're on one of those controllers which doesn't support | 4602 | if (rc < 0) |
4542 | * the doorbell reset method and on which the PCI power management reset | 4603 | goto unmap_cfgtable; |
4543 | * method doesn't work (P800, for example.) | 4604 | if (rc) { |
4544 | * In those cases, don't try to proceed, as it generally doesn't work. | ||
4545 | */ | ||
4546 | active_transport = readl(&cfgtable->TransportActive); | ||
4547 | if (active_transport & PERFORMANT_MODE) { | ||
4548 | dev_warn(&pdev->dev, "Unable to successfully reset controller," | 4605 | dev_warn(&pdev->dev, "Unable to successfully reset controller," |
4549 | " Ignoring controller.\n"); | 4606 | " Ignoring controller.\n"); |
4550 | rc = -ENODEV; | 4607 | rc = -ENODEV; |
4608 | goto unmap_cfgtable; | ||
4609 | } else { | ||
4610 | dev_info(&pdev->dev, "board ready.\n"); | ||
4551 | } | 4611 | } |
4552 | 4612 | ||
4613 | dev_info(&pdev->dev, "board ready.\n"); | ||
4614 | |||
4553 | unmap_cfgtable: | 4615 | unmap_cfgtable: |
4554 | iounmap(cfgtable); | 4616 | iounmap(cfgtable); |
4555 | 4617 | ||
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index cd441bef031f..a2e68d21efe3 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h | |||
@@ -235,6 +235,7 @@ typedef struct _CfgTable_struct { | |||
235 | u8 reserved[0x78 - 0x58]; | 235 | u8 reserved[0x78 - 0x58]; |
236 | u32 misc_fw_support; /* offset 0x78 */ | 236 | u32 misc_fw_support; /* offset 0x78 */ |
237 | #define MISC_FW_DOORBELL_RESET (0x02) | 237 | #define MISC_FW_DOORBELL_RESET (0x02) |
238 | u8 driver_version[32]; | ||
238 | } CfgTable_struct; | 239 | } CfgTable_struct; |
239 | 240 | ||
240 | struct TransTable_struct { | 241 | struct TransTable_struct { |