+/*
+# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+# until the timer expires. Value range is [0,255]. Default value is 30.
+*/
+static int lpfc_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+static int lpfc_devloss_tmo = LPFC_DEF_DEVLOSS_TMO;
+module_param(lpfc_nodev_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_nodev_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+static ssize_t
+lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int val = 0;
+ val = phba->cfg_devloss_tmo;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->cfg_devloss_tmo);
+}
+
+static int
+lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
+{
+ static int warned;
+ if (phba->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
+ if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
+ warned = 1;
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0402 Ignoring nodev_tmo module "
+ "parameter because devloss_tmo is"
+ " set.\n",
+ phba->brd_no);
+ }
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
+ phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+ return -EINVAL;
+}
+
+static int
+lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (phba->dev_loss_tmo_changed ||
+ (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0401 Ignoring change to nodev_tmo "
+ "because devloss_tmo is set.\n",
+ phba->brd_no);
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(nodev_tmo)
+
+static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
+ lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
+
+/*
+# lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that
+# disappear until the timer expires. Value range is [0,255]. Default
+# value is 30.
+*/
+module_param(lpfc_devloss_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_devloss_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
+lpfc_param_show(devloss_tmo)
+static int
+lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ phba->dev_loss_tmo_changed = 1;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0404 lpfc_devloss_tmo attribute cannot be set to"
+ " %d, allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(devloss_tmo)
+static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
+ lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
+