Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: aacraid: Fix driver oops with dead battery

The battery in my HP NetRAID-4M died of old age, and the aacraid driver
started oopsing with NULL pointer dereference on startup after that.

Fix it by reordering the init sequence to fill in function pointers
before ioremapping memory, or dev->a_ops.adapter_ioremap pointer will be
NULL.

Other subtypes of aacraid seem to have the order already correct.

This was the call trace:

? aac_probe_one+0x7a5/0xb30 [aacraid]
pci_device_probe+0xc0/0x1a0
driver_probe_device+0x1df/0x3b0
__driver_attach+0xa9/0xe0
? driver_probe_device+0x3b0/0x3b0
bus_for_each_dev+0x4c/0x90
driver_attach+0x1d/0x40
? driver_probe_device+0x3b0/0x3b0
bus_add_driver+0x1a7/0x2a0
driver_register+0x6e/0x130
__pci_register_driver+0x54/0x90
? 0xf81f4000
aac_init+0x2b/0x1000 [aacraid]
do_one_initcall+0x45/0x1e0
? kfree_skbmem+0x74/0xa0
? kfree+0x16d/0x240
? kvfree+0x45/0x50
? kvfree+0x45/0x50
? __vunmap+0x99/0x120
? do_init_module+0x1a/0x245
do_init_module+0x83/0x245
load_module+0x2764/0x34a0
? kernel_read_file+0x150/0x320
SyS_finit_module+0x82/0xa0
do_fast_syscall_32+0xba/0x340

Signed-off-by: Meelis Roos <mroos@linux.ee>
Reviewed-by: Raghava Aditya Renukunta <RaghavaAditya.Renukunta@microsemi.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Meelis Roos and committed by
Martin K. Petersen
bef4e688 1d1db6a3

+16 -16
+16 -16
drivers/scsi/aacraid/sa.c
··· 329 329 instance = dev->id; 330 330 name = dev->name; 331 331 332 + /* 333 + * Fill in the function dispatch table. 334 + */ 335 + 336 + dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; 337 + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; 338 + dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; 339 + dev->a_ops.adapter_notify = aac_sa_notify_adapter; 340 + dev->a_ops.adapter_sync_cmd = sa_sync_cmd; 341 + dev->a_ops.adapter_check_health = aac_sa_check_health; 342 + dev->a_ops.adapter_restart = aac_sa_restart_adapter; 343 + dev->a_ops.adapter_start = aac_sa_start_adapter; 344 + dev->a_ops.adapter_intr = aac_sa_intr; 345 + dev->a_ops.adapter_deliver = aac_rx_deliver_producer; 346 + dev->a_ops.adapter_ioremap = aac_sa_ioremap; 347 + 332 348 if (aac_sa_ioremap(dev, dev->base_size)) { 333 349 printk(KERN_WARNING "%s: unable to map adapter.\n", name); 334 350 goto error_iounmap; ··· 377 361 } 378 362 msleep(1); 379 363 } 380 - 381 - /* 382 - * Fill in the function dispatch table. 383 - */ 384 - 385 - dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; 386 - dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; 387 - dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; 388 - dev->a_ops.adapter_notify = aac_sa_notify_adapter; 389 - dev->a_ops.adapter_sync_cmd = sa_sync_cmd; 390 - dev->a_ops.adapter_check_health = aac_sa_check_health; 391 - dev->a_ops.adapter_restart = aac_sa_restart_adapter; 392 - dev->a_ops.adapter_start = aac_sa_start_adapter; 393 - dev->a_ops.adapter_intr = aac_sa_intr; 394 - dev->a_ops.adapter_deliver = aac_rx_deliver_producer; 395 - dev->a_ops.adapter_ioremap = aac_sa_ioremap; 396 364 397 365 /* 398 366 * First clear out all interrupts. Then enable the one's that