scsi: qedi: Fix firmware halt over suspend and resume

While performing certain power-off sequences, PCI drivers are called to
suspend and resume their underlying devices through PCI PM (power
management) interface. However the hardware does not support PCI PM
suspend/resume operations so system wide suspend/resume leads to bad MFW
(management firmware) state which causes various follow-up errors in driver
when communicating with the device/firmware.

To fix this driver implements PCI PM suspend handler to indicate
unsupported operation to the PCI subsystem explicitly, thus avoiding system
to go into suspended/standby mode.

Fixes: ace7f46ba5fd ("scsi: qedi: Add QLogic FastLinQ offload iSCSI driver framework.")
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20230807093725.46829-2-njavali@marvell.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Nilesh Javali and committed by
Martin K. Petersen
1516ee03 dd64f805

+18
+18
drivers/scsi/qedi/qedi_main.c
··· 69 static void qedi_recovery_handler(struct work_struct *work); 70 static void qedi_schedule_hw_err_handler(void *dev, 71 enum qed_hw_err_type err_type); 72 73 static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) 74 { ··· 2512 __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); 2513 } 2514 2515 static int __qedi_probe(struct pci_dev *pdev, int mode) 2516 { 2517 struct qedi_ctx *qedi; ··· 2886 .remove = qedi_remove, 2887 .shutdown = qedi_shutdown, 2888 .err_handler = &qedi_err_handler, 2889 }; 2890 2891 static int __init qedi_init(void)
··· 69 static void qedi_recovery_handler(struct work_struct *work); 70 static void qedi_schedule_hw_err_handler(void *dev, 71 enum qed_hw_err_type err_type); 72 + static int qedi_suspend(struct pci_dev *pdev, pm_message_t state); 73 74 static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) 75 { ··· 2511 __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); 2512 } 2513 2514 + static int qedi_suspend(struct pci_dev *pdev, pm_message_t state) 2515 + { 2516 + struct qedi_ctx *qedi; 2517 + 2518 + if (!pdev) { 2519 + QEDI_ERR(NULL, "pdev is NULL.\n"); 2520 + return -ENODEV; 2521 + } 2522 + 2523 + qedi = pci_get_drvdata(pdev); 2524 + 2525 + QEDI_ERR(&qedi->dbg_ctx, "%s: Device does not support suspend operation\n", __func__); 2526 + 2527 + return -EPERM; 2528 + } 2529 + 2530 static int __qedi_probe(struct pci_dev *pdev, int mode) 2531 { 2532 struct qedi_ctx *qedi; ··· 2869 .remove = qedi_remove, 2870 .shutdown = qedi_shutdown, 2871 .err_handler = &qedi_err_handler, 2872 + .suspend = qedi_suspend, 2873 }; 2874 2875 static int __init qedi_init(void)