[SCSI] megaraid_sas: Add three times Online controller reset

If fw didn't raise the interrupt with the fw state change to driver
and fw goes to failure state, driver Will check the FW state in
driver's timeout routine and issue the reset if need. Driver will do
the OCR upto three times until kill adapter. Also driver will issue
OCR before driver kill adapter even if fw in operational state.

Signed-off-by Bo Yang <bo.yang@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>

authored by Yang, Bo and committed by James Bottomley 707e09bd 1fd10685

+69 -1
+69 -1
drivers/scsi/megaraid/megaraid_sas.c
··· 728 megasas_check_reset_gen2(struct megasas_instance *instance, 729 struct megasas_register_set __iomem *regs) 730 { 731 return 0; 732 } 733 ··· 944 mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl); 945 mfi_sgl->sge_skinny[i].phys_addr = 946 sg_dma_address(os_sgl); 947 } 948 } 949 return sge_count; ··· 1572 } 1573 } 1574 1575 /** 1576 * megasas_wait_for_outstanding - Wait for all outstanding cmds 1577 * @instance: Adapter soft state ··· 1611 unsigned long flags; 1612 struct list_head clist_local; 1613 struct megasas_cmd *reset_cmd; 1614 1615 spin_lock_irqsave(&instance->hba_lock, flags); 1616 adprecovery = instance->adprecovery; ··· 1698 msleep(1000); 1699 } 1700 1701 - if (atomic_read(&instance->fw_outstanding)) { 1702 printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); 1703 /* 1704 * Send signal to FW to stop processing any pending cmds. ··· 2746 return -ENOMEM; 2747 } 2748 2749 cmd->frame->io.context = cmd->index; 2750 cmd->frame->io.pad_0 = 0; 2751 }
··· 728 megasas_check_reset_gen2(struct megasas_instance *instance, 729 struct megasas_register_set __iomem *regs) 730 { 731 + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { 732 + return 1; 733 + } 734 + 735 return 0; 736 } 737 ··· 940 mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl); 941 mfi_sgl->sge_skinny[i].phys_addr = 942 sg_dma_address(os_sgl); 943 + mfi_sgl->sge_skinny[i].flag = 0; 944 } 945 } 946 return sge_count; ··· 1567 } 1568 } 1569 1570 + static void 1571 + megasas_internal_reset_defer_cmds(struct megasas_instance *instance); 1572 + 1573 + static void 1574 + process_fw_state_change_wq(struct work_struct *work); 1575 + 1576 + void megasas_do_ocr(struct megasas_instance *instance) 1577 + { 1578 + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || 1579 + (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || 1580 + (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) { 1581 + *instance->consumer = MEGASAS_ADPRESET_INPROG_SIGN; 1582 + } 1583 + instance->instancet->disable_intr(instance->reg_set); 1584 + instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; 1585 + instance->issuepend_done = 0; 1586 + 1587 + atomic_set(&instance->fw_outstanding, 0); 1588 + megasas_internal_reset_defer_cmds(instance); 1589 + process_fw_state_change_wq(&instance->work_init); 1590 + } 1591 + 1592 /** 1593 * megasas_wait_for_outstanding - Wait for all outstanding cmds 1594 * @instance: Adapter soft state ··· 1584 unsigned long flags; 1585 struct list_head clist_local; 1586 struct megasas_cmd *reset_cmd; 1587 + u32 fw_state; 1588 + u8 kill_adapter_flag; 1589 1590 spin_lock_irqsave(&instance->hba_lock, flags); 1591 adprecovery = instance->adprecovery; ··· 1669 msleep(1000); 1670 } 1671 1672 + i = 0; 1673 + kill_adapter_flag = 0; 1674 + do { 1675 + fw_state = instance->instancet->read_fw_status_reg( 1676 + instance->reg_set) & MFI_STATE_MASK; 1677 + if ((fw_state == MFI_STATE_FAULT) && 1678 + (instance->disableOnlineCtrlReset == 0)) { 1679 + if (i == 3) { 1680 + kill_adapter_flag = 2; 1681 + break; 1682 + } 1683 + megasas_do_ocr(instance); 1684 + kill_adapter_flag = 1; 1685 + 1686 + /* wait for 1 secs to let FW finish the pending cmds */ 1687 + msleep(1000); 1688 + } 1689 + i++; 1690 + } while (i <= 3); 1691 + 1692 + if (atomic_read(&instance->fw_outstanding) && 1693 + !kill_adapter_flag) { 1694 + if (instance->disableOnlineCtrlReset == 0) { 1695 + 1696 + megasas_do_ocr(instance); 1697 + 1698 + /* wait for 5 secs to let FW finish the pending cmds */ 1699 + for (i = 0; i < wait_time; i++) { 1700 + int outstanding = 1701 + atomic_read(&instance->fw_outstanding); 1702 + if (!outstanding) 1703 + return SUCCESS; 1704 + msleep(1000); 1705 + } 1706 + } 1707 + } 1708 + 1709 + if (atomic_read(&instance->fw_outstanding) || 1710 + (kill_adapter_flag == 2)) { 1711 printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); 1712 /* 1713 * Send signal to FW to stop processing any pending cmds. ··· 2679 return -ENOMEM; 2680 } 2681 2682 + memset(cmd->frame, 0, total_sz); 2683 cmd->frame->io.context = cmd->index; 2684 cmd->frame->io.pad_0 = 0; 2685 }