diff options
-rw-r--r-- | drivers/scsi/hpsa.c | 76 | ||||
-rw-r--r-- | drivers/scsi/hpsa_cmd.h | 1 |
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 | ||
3187 | static __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 | |||
3193 | static __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 | |||
3210 | static __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 | |||
3219 | static __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 | ||
3307 | unmap_cfgtable: | 3360 | unmap_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 |