@@ -5546,6 +5546,197 @@ mpi3mr_resume(struct device *dev)
5546
5546
return 0 ;
5547
5547
}
5548
5548
5549
+ /**
5550
+ * mpi3mr_pcierr_error_detected - PCI error detected callback
5551
+ * @pdev: PCI device instance
5552
+ * @state: channel state
5553
+ *
5554
+ * This function is called by the PCI error recovery driver and
5555
+ * based on the state passed the driver decides what actions to
5556
+ * be recommended back to PCI driver.
5557
+ *
5558
+ * For all of the states if there is no valid mrioc or scsi host
5559
+ * references in the PCI device then this function will return
5560
+ * the result as disconnect.
5561
+ *
5562
+ * For normal state, this function will return the result as can
5563
+ * recover.
5564
+ *
5565
+ * For frozen state, this function will block for any pending
5566
+ * controller initialization or re-initialization to complete,
5567
+ * stop any new interactions with the controller and return
5568
+ * status as reset required.
5569
+ *
5570
+ * For permanent failure state, this function will mark the
5571
+ * controller as unrecoverable and return status as disconnect.
5572
+ *
5573
+ * Returns: PCI_ERS_RESULT_NEED_RESET or CAN_RECOVER or
5574
+ * DISCONNECT based on the controller state.
5575
+ */
5576
+ static pci_ers_result_t
5577
+ mpi3mr_pcierr_error_detected (struct pci_dev * pdev , pci_channel_state_t state )
5578
+ {
5579
+ struct Scsi_Host * shost ;
5580
+ struct mpi3mr_ioc * mrioc ;
5581
+ unsigned int timeout = MPI3MR_RESET_TIMEOUT ;
5582
+
5583
+ dev_info (& pdev -> dev , "%s: callback invoked state(%d)\n" , __func__ ,
5584
+ state );
5585
+
5586
+ shost = pci_get_drvdata (pdev );
5587
+ mrioc = shost_priv (shost );
5588
+
5589
+ switch (state ) {
5590
+ case pci_channel_io_normal :
5591
+ return PCI_ERS_RESULT_CAN_RECOVER ;
5592
+ case pci_channel_io_frozen :
5593
+ mrioc -> pci_err_recovery = true;
5594
+ mrioc -> block_on_pci_err = true;
5595
+ do {
5596
+ if (mrioc -> reset_in_progress || mrioc -> is_driver_loading )
5597
+ ssleep (1 );
5598
+ else
5599
+ break ;
5600
+ } while (-- timeout );
5601
+
5602
+ if (!timeout ) {
5603
+ mrioc -> pci_err_recovery = true;
5604
+ mrioc -> block_on_pci_err = true;
5605
+ mrioc -> unrecoverable = 1 ;
5606
+ mpi3mr_stop_watchdog (mrioc );
5607
+ mpi3mr_flush_cmds_for_unrecovered_controller (mrioc );
5608
+ return PCI_ERS_RESULT_DISCONNECT ;
5609
+ }
5610
+
5611
+ scsi_block_requests (mrioc -> shost );
5612
+ mpi3mr_stop_watchdog (mrioc );
5613
+ mpi3mr_cleanup_resources (mrioc );
5614
+ return PCI_ERS_RESULT_NEED_RESET ;
5615
+ case pci_channel_io_perm_failure :
5616
+ mrioc -> pci_err_recovery = true;
5617
+ mrioc -> block_on_pci_err = true;
5618
+ mrioc -> unrecoverable = 1 ;
5619
+ mpi3mr_stop_watchdog (mrioc );
5620
+ mpi3mr_flush_cmds_for_unrecovered_controller (mrioc );
5621
+ return PCI_ERS_RESULT_DISCONNECT ;
5622
+ default :
5623
+ return PCI_ERS_RESULT_DISCONNECT ;
5624
+ }
5625
+ }
5626
+
5627
+ /**
5628
+ * mpi3mr_pcierr_slot_reset - Post slot reset callback
5629
+ * @pdev: PCI device instance
5630
+ *
5631
+ * This function is called by the PCI error recovery driver
5632
+ * after a slot or link reset issued by it for the recovery, the
5633
+ * driver is expected to bring back the controller and
5634
+ * initialize it.
5635
+ *
5636
+ * This function restores PCI state and reinitializes controller
5637
+ * resources and the controller, this blocks for any pending
5638
+ * reset to complete.
5639
+ *
5640
+ * Returns: PCI_ERS_RESULT_DISCONNECT on failure or
5641
+ * PCI_ERS_RESULT_RECOVERED
5642
+ */
5643
+ static pci_ers_result_t mpi3mr_pcierr_slot_reset (struct pci_dev * pdev )
5644
+ {
5645
+ struct Scsi_Host * shost ;
5646
+ struct mpi3mr_ioc * mrioc ;
5647
+ unsigned int timeout = MPI3MR_RESET_TIMEOUT ;
5648
+
5649
+ dev_info (& pdev -> dev , "%s: callback invoked\n" , __func__ );
5650
+
5651
+ shost = pci_get_drvdata (pdev );
5652
+ mrioc = shost_priv (shost );
5653
+
5654
+ do {
5655
+ if (mrioc -> reset_in_progress )
5656
+ ssleep (1 );
5657
+ else
5658
+ break ;
5659
+ } while (-- timeout );
5660
+
5661
+ if (!timeout )
5662
+ goto out_failed ;
5663
+
5664
+ pci_restore_state (pdev );
5665
+
5666
+ if (mpi3mr_setup_resources (mrioc )) {
5667
+ ioc_err (mrioc , "setup resources failed\n" );
5668
+ goto out_failed ;
5669
+ }
5670
+ mrioc -> unrecoverable = 0 ;
5671
+ mrioc -> pci_err_recovery = false;
5672
+
5673
+ if (mpi3mr_soft_reset_handler (mrioc , MPI3MR_RESET_FROM_FIRMWARE , 0 ))
5674
+ goto out_failed ;
5675
+
5676
+ return PCI_ERS_RESULT_RECOVERED ;
5677
+
5678
+ out_failed :
5679
+ mrioc -> unrecoverable = 1 ;
5680
+ mrioc -> block_on_pci_err = false;
5681
+ scsi_unblock_requests (shost );
5682
+ mpi3mr_start_watchdog (mrioc );
5683
+ return PCI_ERS_RESULT_DISCONNECT ;
5684
+ }
5685
+
5686
+ /**
5687
+ * mpi3mr_pcierr_resume - PCI error recovery resume
5688
+ * callback
5689
+ * @pdev: PCI device instance
5690
+ *
5691
+ * This function enables all I/O and IOCTLs post reset issued as
5692
+ * part of the PCI error recovery
5693
+ *
5694
+ * Return: Nothing.
5695
+ */
5696
+ static void mpi3mr_pcierr_resume (struct pci_dev * pdev )
5697
+ {
5698
+ struct Scsi_Host * shost ;
5699
+ struct mpi3mr_ioc * mrioc ;
5700
+
5701
+ dev_info (& pdev -> dev , "%s: callback invoked\n" , __func__ );
5702
+
5703
+ shost = pci_get_drvdata (pdev );
5704
+ mrioc = shost_priv (shost );
5705
+
5706
+ if (mrioc -> block_on_pci_err ) {
5707
+ mrioc -> block_on_pci_err = false;
5708
+ scsi_unblock_requests (shost );
5709
+ mpi3mr_start_watchdog (mrioc );
5710
+ }
5711
+ }
5712
+
5713
+ /**
5714
+ * mpi3mr_pcierr_mmio_enabled - PCI error recovery callback
5715
+ * @pdev: PCI device instance
5716
+ *
5717
+ * This is called only if mpi3mr_pcierr_error_detected returns
5718
+ * PCI_ERS_RESULT_CAN_RECOVER.
5719
+ *
5720
+ * Return: PCI_ERS_RESULT_DISCONNECT when the controller is
5721
+ * unrecoverable or when the shost/mrioc reference cannot be
5722
+ * found, else return PCI_ERS_RESULT_RECOVERED
5723
+ */
5724
+ static pci_ers_result_t mpi3mr_pcierr_mmio_enabled (struct pci_dev * pdev )
5725
+ {
5726
+ struct Scsi_Host * shost ;
5727
+ struct mpi3mr_ioc * mrioc ;
5728
+
5729
+ dev_info (& pdev -> dev , "%s: callback invoked\n" , __func__ );
5730
+
5731
+ shost = pci_get_drvdata (pdev );
5732
+ mrioc = shost_priv (shost );
5733
+
5734
+ if (mrioc -> unrecoverable )
5735
+ return PCI_ERS_RESULT_DISCONNECT ;
5736
+
5737
+ return PCI_ERS_RESULT_RECOVERED ;
5738
+ }
5739
+
5549
5740
static const struct pci_device_id mpi3mr_pci_id_table [] = {
5550
5741
{
5551
5742
PCI_DEVICE_SUB (MPI3_MFGPAGE_VENDORID_BROADCOM ,
@@ -5563,6 +5754,13 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = {
5563
5754
};
5564
5755
MODULE_DEVICE_TABLE (pci , mpi3mr_pci_id_table );
5565
5756
5757
+ static struct pci_error_handlers mpi3mr_err_handler = {
5758
+ .error_detected = mpi3mr_pcierr_error_detected ,
5759
+ .mmio_enabled = mpi3mr_pcierr_mmio_enabled ,
5760
+ .slot_reset = mpi3mr_pcierr_slot_reset ,
5761
+ .resume = mpi3mr_pcierr_resume ,
5762
+ };
5763
+
5566
5764
static SIMPLE_DEV_PM_OPS (mpi3mr_pm_ops , mpi3mr_suspend , mpi3mr_resume ) ;
5567
5765
5568
5766
static struct pci_driver mpi3mr_pci_driver = {
@@ -5571,6 +5769,7 @@ static struct pci_driver mpi3mr_pci_driver = {
5571
5769
.probe = mpi3mr_probe ,
5572
5770
.remove = mpi3mr_remove ,
5573
5771
.shutdown = mpi3mr_shutdown ,
5772
+ .err_handler = & mpi3mr_err_handler ,
5574
5773
.driver .pm = & mpi3mr_pm_ops ,
5575
5774
};
5576
5775
0 commit comments