Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 336b6819 authored by Kevin Barnett's avatar Kevin Barnett Committed by Martin K. Petersen
Browse files

scsi: smartpqi: add pqi reset quiesce support

parent 0b7250f9
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -688,6 +688,28 @@ struct pqi_config_table_heartbeat {
	__le32	heartbeat_counter;
};

union pqi_reset_register {
	struct {
		u32	reset_type : 3;
		u32	reserved : 2;
		u32	reset_action : 3;
		u32	hold_in_pd1 : 1;
		u32	reserved2 : 23;
	} bits;
	u32	all_bits;
};

#define PQI_RESET_ACTION_RESET		0x1

#define PQI_RESET_TYPE_NO_RESET		0x0
#define PQI_RESET_TYPE_SOFT_RESET	0x1
#define PQI_RESET_TYPE_FIRM_RESET	0x2
#define PQI_RESET_TYPE_HARD_RESET	0x3

#define PQI_RESET_ACTION_COMPLETED	0x2

#define PQI_RESET_POLL_INTERVAL_MSECS	100

#define PQI_MAX_OUTSTANDING_REQUESTS		((u32)~0)
#define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP	32
#define PQI_MAX_TRANSFER_SIZE			(1024U * 1024U)
@@ -995,6 +1017,7 @@ struct pqi_ctrl_info {
	u8		inbound_spanning_supported : 1;
	u8		outbound_spanning_supported : 1;
	u8		pqi_mode_enabled : 1;
	u8		pqi_reset_quiesce_supported : 1;

	struct list_head scsi_device_list;
	spinlock_t	scsi_device_list_lock;
+46 −12
Original line number Diff line number Diff line
@@ -5889,28 +5889,62 @@ static void pqi_unregister_scsi(struct pqi_ctrl_info *ctrl_info)
	scsi_host_put(shost);
}

#define PQI_RESET_ACTION_RESET		0x1
static int pqi_wait_for_pqi_reset_completion(struct pqi_ctrl_info *ctrl_info)
{
	int rc = 0;
	struct pqi_device_registers __iomem *pqi_registers;
	unsigned long timeout;
	unsigned int timeout_msecs;
	union pqi_reset_register reset_reg;

	pqi_registers = ctrl_info->pqi_registers;
	timeout_msecs = readw(&pqi_registers->max_reset_timeout) * 100;
	timeout = msecs_to_jiffies(timeout_msecs) + jiffies;

	while (1) {
		msleep(PQI_RESET_POLL_INTERVAL_MSECS);
		reset_reg.all_bits = readl(&pqi_registers->device_reset);
		if (reset_reg.bits.reset_action == PQI_RESET_ACTION_COMPLETED)
			break;
		pqi_check_ctrl_health(ctrl_info);
		if (pqi_ctrl_offline(ctrl_info)) {
			rc = -ENXIO;
			break;
		}
		if (time_after(jiffies, timeout)) {
			rc = -ETIMEDOUT;
			break;
		}
	}

#define PQI_RESET_TYPE_NO_RESET		0x0
#define PQI_RESET_TYPE_SOFT_RESET	0x1
#define PQI_RESET_TYPE_FIRM_RESET	0x2
#define PQI_RESET_TYPE_HARD_RESET	0x3
	return rc;
}

static int pqi_reset(struct pqi_ctrl_info *ctrl_info)
{
	int rc;
	u32 reset_params;
	union pqi_reset_register reset_reg;

	reset_params = (PQI_RESET_ACTION_RESET << 5) |
		PQI_RESET_TYPE_HARD_RESET;
	if (ctrl_info->pqi_reset_quiesce_supported) {
		rc = sis_pqi_reset_quiesce(ctrl_info);
		if (rc) {
			dev_err(&ctrl_info->pci_dev->dev,
				"PQI reset failed during quiesce with error %d\n",
				rc);
			return rc;
		}
	}

	writel(reset_params,
		&ctrl_info->pqi_registers->device_reset);
	reset_reg.all_bits = 0;
	reset_reg.bits.reset_type = PQI_RESET_TYPE_HARD_RESET;
	reset_reg.bits.reset_action = PQI_RESET_ACTION_RESET;

	rc = pqi_wait_for_pqi_mode_ready(ctrl_info);
	writel(reset_reg.all_bits, &ctrl_info->pqi_registers->device_reset);

	rc = pqi_wait_for_pqi_reset_completion(ctrl_info);
	if (rc)
		dev_err(&ctrl_info->pci_dev->dev,
			"PQI reset failed\n");
			"PQI reset failed with error %d\n", rc);

	return rc;
}
+28 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#define SIS_ENABLE_INTX				0x80
#define SIS_SOFT_RESET				0x100
#define SIS_TRIGGER_SHUTDOWN			0x800000
#define SIS_PQI_RESET_QUIESCE			0x1000000
#define SIS_CMD_READY				0x200
#define SIS_CMD_COMPLETE			0x1000
#define SIS_CLEAR_CTRL_TO_HOST_DOORBELL		0x1000
@@ -47,6 +48,7 @@
#define SIS_EXTENDED_PROPERTIES_SUPPORTED	0x800000
#define SIS_SMARTARRAY_FEATURES_SUPPORTED	0x2
#define SIS_PQI_MODE_SUPPORTED			0x4
#define SIS_PQI_RESET_QUIESCE_SUPPORTED		0x8
#define SIS_REQUIRED_EXTENDED_PROPERTIES	\
	(SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED)

@@ -258,6 +260,9 @@ int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info)
		SIS_REQUIRED_EXTENDED_PROPERTIES)
		return -ENODEV;

	if (extended_properties & SIS_PQI_RESET_QUIESCE_SUPPORTED)
		ctrl_info->pqi_reset_quiesce_supported = true;

	return 0;
}

@@ -336,9 +341,10 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info)

#define SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS	30

static void sis_wait_for_doorbell_bit_to_clear(
static int sis_wait_for_doorbell_bit_to_clear(
	struct pqi_ctrl_info *ctrl_info, u32 bit)
{
	int rc = 0;
	u32 doorbell_register;
	unsigned long timeout;

@@ -350,16 +356,21 @@ static void sis_wait_for_doorbell_bit_to_clear(
		if ((doorbell_register & bit) == 0)
			break;
		if (readl(&ctrl_info->registers->sis_firmware_status) &
			SIS_CTRL_KERNEL_PANIC)
			SIS_CTRL_KERNEL_PANIC) {
			rc = -ENODEV;
			break;
		}
		if (time_after(jiffies, timeout)) {
			dev_err(&ctrl_info->pci_dev->dev,
				"doorbell register bit 0x%x not cleared\n",
				bit);
			rc = -ETIMEDOUT;
			break;
		}
		usleep_range(1000, 2000);
	}

	return rc;
}

/* Enable MSI-X interrupts on the controller. */
@@ -434,6 +445,21 @@ void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info)
		&ctrl_info->registers->sis_host_to_ctrl_doorbell);
}

int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info)
{
	u32 doorbell_register;

	doorbell_register =
		readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
	doorbell_register |= SIS_PQI_RESET_QUIESCE;

	writel(doorbell_register,
		&ctrl_info->registers->sis_host_to_ctrl_doorbell);

	return sis_wait_for_doorbell_bit_to_clear(ctrl_info,
		SIS_PQI_RESET_QUIESCE);
}

#define SIS_MODE_READY_TIMEOUT_SECS	30

int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info)
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ void sis_enable_intx(struct pqi_ctrl_info *ctrl_info);
void sis_disable_intx(struct pqi_ctrl_info *ctrl_info);
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info);
int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info);
int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);