aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/hpsa.c76
-rw-r--r--drivers/scsi/hpsa_cmd.h1
2 files changed, 67 insertions, 10 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 82668505ccbb..2aeb21094b45 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3184,6 +3184,59 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
3184 return 0; 3184 return 0;
3185} 3185}
3186 3186
3187static __devinit void init_driver_version(char *driver_version, int len)
3188{
3189 memset(driver_version, 0, len);
3190 strncpy(driver_version, "hpsa " HPSA_DRIVER_VERSION, len - 1);
3191}
3192
3193static __devinit int write_driver_ver_to_cfgtable(
3194 struct CfgTable __iomem *cfgtable)
3195{
3196 char *driver_version;
3197 int i, size = sizeof(cfgtable->driver_version);
3198
3199 driver_version = kmalloc(size, GFP_KERNEL);
3200 if (!driver_version)
3201 return -ENOMEM;
3202
3203 init_driver_version(driver_version, size);
3204 for (i = 0; i < size; i++)
3205 writeb(driver_version[i], &cfgtable->driver_version[i]);
3206 kfree(driver_version);
3207 return 0;
3208}
3209
3210static __devinit void read_driver_ver_from_cfgtable(
3211 struct CfgTable __iomem *cfgtable, unsigned char *driver_ver)
3212{
3213 int i;
3214
3215 for (i = 0; i < sizeof(cfgtable->driver_version); i++)
3216 driver_ver[i] = readb(&cfgtable->driver_version[i]);
3217}
3218
3219static __devinit int controller_reset_failed(
3220 struct CfgTable __iomem *cfgtable)
3221{
3222
3223 char *driver_ver, *old_driver_ver;
3224 int rc, size = sizeof(cfgtable->driver_version);
3225
3226 old_driver_ver = kmalloc(2 * size, GFP_KERNEL);
3227 if (!old_driver_ver)
3228 return -ENOMEM;
3229 driver_ver = old_driver_ver + size;
3230
3231 /* After a reset, the 32 bytes of "driver version" in the cfgtable
3232 * should have been changed, otherwise we know the reset failed.
3233 */
3234 init_driver_version(old_driver_ver, size);
3235 read_driver_ver_from_cfgtable(cfgtable, driver_ver);
3236 rc = !memcmp(driver_ver, old_driver_ver, size);
3237 kfree(old_driver_ver);
3238 return rc;
3239}
3187/* This does a hard reset of the controller using PCI power management 3240/* This does a hard reset of the controller using PCI power management
3188 * states or the using the doorbell register. 3241 * states or the using the doorbell register.
3189 */ 3242 */
@@ -3194,7 +3247,7 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
3194 u64 cfg_base_addr_index; 3247 u64 cfg_base_addr_index;
3195 void __iomem *vaddr; 3248 void __iomem *vaddr;
3196 unsigned long paddr; 3249 unsigned long paddr;
3197 u32 misc_fw_support, active_transport; 3250 u32 misc_fw_support;
3198 int rc; 3251 int rc;
3199 struct CfgTable __iomem *cfgtable; 3252 struct CfgTable __iomem *cfgtable;
3200 bool use_doorbell; 3253 bool use_doorbell;
@@ -3256,6 +3309,9 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
3256 rc = -ENOMEM; 3309 rc = -ENOMEM;
3257 goto unmap_vaddr; 3310 goto unmap_vaddr;
3258 } 3311 }
3312 rc = write_driver_ver_to_cfgtable(cfgtable);
3313 if (rc)
3314 goto unmap_vaddr;
3259 3315
3260 /* If reset via doorbell register is supported, use that. */ 3316 /* If reset via doorbell register is supported, use that. */
3261 misc_fw_support = readl(&cfgtable->misc_fw_support); 3317 misc_fw_support = readl(&cfgtable->misc_fw_support);
@@ -3289,19 +3345,16 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
3289 "failed waiting for board to become ready\n"); 3345 "failed waiting for board to become ready\n");
3290 goto unmap_cfgtable; 3346 goto unmap_cfgtable;
3291 } 3347 }
3292 dev_info(&pdev->dev, "board ready.\n");
3293 3348
3294 /* Controller should be in simple mode at this point. If it's not, 3349 rc = controller_reset_failed(vaddr);
3295 * It means we're on one of those controllers which doesn't support 3350 if (rc < 0)
3296 * the doorbell reset method and on which the PCI power management reset 3351 goto unmap_cfgtable;
3297 * method doesn't work (P800, for example.) 3352 if (rc) {
3298 * In those cases, don't try to proceed, as it generally doesn't work.
3299 */
3300 active_transport = readl(&cfgtable->TransportActive);
3301 if (active_transport & PERFORMANT_MODE) {
3302 dev_warn(&pdev->dev, "Unable to successfully reset controller," 3353 dev_warn(&pdev->dev, "Unable to successfully reset controller,"
3303 " Ignoring controller.\n"); 3354 " Ignoring controller.\n");
3304 rc = -ENODEV; 3355 rc = -ENODEV;
3356 } else {
3357 dev_info(&pdev->dev, "board ready.\n");
3305 } 3358 }
3306 3359
3307unmap_cfgtable: 3360unmap_cfgtable:
@@ -3542,6 +3595,9 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
3542 cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); 3595 cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
3543 if (!h->cfgtable) 3596 if (!h->cfgtable)
3544 return -ENOMEM; 3597 return -ENOMEM;
3598 rc = write_driver_ver_to_cfgtable(h->cfgtable);
3599 if (rc)
3600 return rc;
3545 /* Find performant mode table. */ 3601 /* Find performant mode table. */
3546 trans_offset = readl(&h->cfgtable->TransMethodOffset); 3602 trans_offset = readl(&h->cfgtable->TransMethodOffset);
3547 h->transtable = remap_pci_mem(pci_resource_start(h->pdev, 3603 h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 05007404f5b0..8fd35a7abcd1 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -337,6 +337,7 @@ struct CfgTable {
337 u8 reserved[0x78 - 0x58]; 337 u8 reserved[0x78 - 0x58];
338 u32 misc_fw_support; /* offset 0x78 */ 338 u32 misc_fw_support; /* offset 0x78 */
339#define MISC_FW_DOORBELL_RESET (0x02) 339#define MISC_FW_DOORBELL_RESET (0x02)
340 u8 driver_version[32];
340}; 341};
341 342
342#define NUM_BLOCKFETCH_ENTRIES 8 343#define NUM_BLOCKFETCH_ENTRIES 8