aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorStephen M. Cameron <scameron@beardog.cce.hp.com>2011-05-03 15:59:10 -0400
committerJames Bottomley <jbottomley@parallels.com>2011-05-17 03:04:11 -0400
commit580ada3c1e2f23b4b0f3c254cae3eb278f92d494 (patch)
treec66b3f9874956d5d2730b091157430d5e584da1e /drivers/scsi
parenta2a431a4fd3b11c6808933ca1bdb2d28a8fa0634 (diff)
[SCSI] hpsa: do a better job of detecting controller reset failure
Detect failure of controller reset by noticing if the 32 bytes of "driver version" we store on the hardware in the config table fail to get zeroed out. Previously we noticed if the controller did not transition to "simple mode", but this did not detect reset failure if the controller was already in simple mode prior to the reset attempt (e.g. due to module parameter hpsa_simple_mode=1). Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: James Bottomley <jbottomley@parallels.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-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