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

cciss: use new doorbell-bit-5 reset method

The bit-2-doorbell reset method seemed to cause (survivable) NMIs
on some systems and (unsurvivable) IOCK NMIs on some G7 servers.
Firmware guys implemented a new doorbell method to alleviate these
problems triggered by bit 5 of the doorbell register. We want to
use it if it's available.

Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>

authored by

Stephen M. Cameron and committed by
Jens Axboe
bf2e2e6b 3e28601f

+16 -11
+14 -11
drivers/block/cciss.c
··· 4384 4384 #define cciss_noop(p) cciss_message(p, 3, 0) 4385 4385 4386 4386 static int cciss_controller_hard_reset(struct pci_dev *pdev, 4387 - void * __iomem vaddr, bool use_doorbell) 4387 + void * __iomem vaddr, u32 use_doorbell) 4388 4388 { 4389 4389 u16 pmcsr; 4390 4390 int pos; ··· 4395 4395 * other way using the doorbell register. 4396 4396 */ 4397 4397 dev_info(&pdev->dev, "using doorbell to reset controller\n"); 4398 - writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL); 4398 + writel(use_doorbell, vaddr + SA5_DOORBELL); 4399 4399 msleep(1000); 4400 4400 } else { /* Try to do it the PCI power state way */ 4401 4401 ··· 4499 4499 u32 misc_fw_support; 4500 4500 int rc; 4501 4501 CfgTable_struct __iomem *cfgtable; 4502 - bool use_doorbell; 4502 + u32 use_doorbell; 4503 4503 u32 board_id; 4504 4504 u16 command_register; 4505 4505 ··· 4560 4560 if (rc) 4561 4561 goto unmap_vaddr; 4562 4562 4563 - /* If reset via doorbell register is supported, use that. */ 4564 - misc_fw_support = readl(&cfgtable->misc_fw_support); 4565 - use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; 4566 - 4567 - /* The doorbell reset seems to cause lockups on some Smart 4568 - * Arrays (e.g. P410, P410i, maybe others). Until this is 4569 - * fixed or at least isolated, avoid the doorbell reset. 4563 + /* If reset via doorbell register is supported, use that. 4564 + * There are two such methods. Favor the newest method. 4570 4565 */ 4571 - use_doorbell = 0; 4566 + misc_fw_support = readl(&cfgtable->misc_fw_support); 4567 + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2; 4568 + if (use_doorbell) { 4569 + use_doorbell = DOORBELL_CTLR_RESET2; 4570 + } else { 4571 + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; 4572 + if (use_doorbell) 4573 + use_doorbell = DOORBELL_CTLR_RESET; 4574 + } 4572 4575 4573 4576 rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell); 4574 4577 if (rc)
+2
drivers/block/cciss_cmd.h
··· 53 53 #define CFGTBL_ChangeReq 0x00000001l 54 54 #define CFGTBL_AccCmds 0x00000001l 55 55 #define DOORBELL_CTLR_RESET 0x00000004l 56 + #define DOORBELL_CTLR_RESET2 0x00000020l 56 57 57 58 #define CFGTBL_Trans_Simple 0x00000002l 58 59 #define CFGTBL_Trans_Performant 0x00000004l ··· 244 243 u8 reserved[0x78 - 0x58]; 245 244 u32 misc_fw_support; /* offset 0x78 */ 246 245 #define MISC_FW_DOORBELL_RESET (0x02) 246 + #define MISC_FW_DOORBELL_RESET2 (0x10) 247 247 u8 driver_version[32]; 248 248 } CfgTable_struct; 249 249