aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/cciss.c82
-rw-r--r--drivers/block/cciss_cmd.h1
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,
194static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, 194static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
195 unsigned long *memory_bar); 195 unsigned long *memory_bar);
196static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag); 196static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag);
197static __devinit int write_driver_ver_to_cfgtable(
198 CfgTable_struct __iomem *cfgtable);
197 199
198/* performant mode helper functions */ 200/* performant mode helper functions */
199static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, 201static 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
4436static __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
4442static __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
4459static __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
4468static __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. */
4433static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) 4492static __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
4553unmap_cfgtable: 4615unmap_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
240struct TransTable_struct { 241struct TransTable_struct {