[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 728 megasas_check_reset_gen2(struct megasas_instance *instance, 729 729 struct megasas_register_set __iomem *regs) 730 730 { 731 + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { 732 + return 1; 733 + } 734 + 731 735 return 0; 732 736 } 733 737 ··· 944 940 mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl); 945 941 mfi_sgl->sge_skinny[i].phys_addr = 946 942 sg_dma_address(os_sgl); 943 + mfi_sgl->sge_skinny[i].flag = 0; 947 944 } 948 945 } 949 946 return sge_count; ··· 1572 1567 } 1573 1568 } 1574 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 + 1575 1592 /** 1576 1593 * megasas_wait_for_outstanding - Wait for all outstanding cmds 1577 1594 * @instance: Adapter soft state ··· 1611 1584 unsigned long flags; 1612 1585 struct list_head clist_local; 1613 1586 struct megasas_cmd *reset_cmd; 1587 + u32 fw_state; 1588 + u8 kill_adapter_flag; 1614 1589 1615 1590 spin_lock_irqsave(&instance->hba_lock, flags); 1616 1591 adprecovery = instance->adprecovery; ··· 1698 1669 msleep(1000); 1699 1670 } 1700 1671 1701 - if (atomic_read(&instance->fw_outstanding)) { 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)) { 1702 1711 printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); 1703 1712 /* 1704 1713 * Send signal to FW to stop processing any pending cmds. ··· 2746 2679 return -ENOMEM; 2747 2680 } 2748 2681 2682 + memset(cmd->frame, 0, total_sz); 2749 2683 cmd->frame->io.context = cmd->index; 2750 2684 cmd->frame->io.pad_0 = 0; 2751 2685 }