[PATCH V2 10/13] pm80xx : IOCTL functionality for SGPIO.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Deepak Ukey <Deepak.Ukey@xxxxxxxxxxxxx>

Added the IOCTL functionality for SGPIO through which management
utility can controls SGPIO LEDs on the enclosure of locally attached
drives only. It is used to read from/write into SGPIO registers and
sets one or more SGPIO registers.

Signed-off-by: Deepak Ukey <deepak.ukey@xxxxxxxxxxxxx>
Signed-off-by: Viswas G <Viswas.G@xxxxxxxxxxxxx>
Signed-off-by: Radha Ramachandran <radha@xxxxxxxxxx>
Reported-by: kbuild test robot <lkp@xxxxxxxxx>
---
 drivers/scsi/pm8001/pm8001_ctl.c  |  71 ++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h  |  72 ++++++++++++++++
 drivers/scsi/pm8001/pm8001_hwi.c  | 172 +++++++++++++++++++++++++++++++++++++-
 drivers/scsi/pm8001/pm8001_hwi.h  |  17 ++++
 drivers/scsi/pm8001/pm8001_init.c |   3 +
 drivers/scsi/pm8001/pm8001_sas.c  |  37 ++++++++
 drivers/scsi/pm8001/pm8001_sas.h  |  20 +++++
 drivers/scsi/pm8001/pm80xx_hwi.c  |   6 ++
 drivers/scsi/pm8001/pm80xx_hwi.h  |   3 +
 9 files changed, 400 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index cadb5be394b6..d557b423edf6 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -1009,6 +1009,74 @@ static long pm8001_gpio_ioctl(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static long pm8001_sgpio_ioctl(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct sgpio_buffer buffer;
+	struct read_write_req_resp *req = &buffer.sgpio_req;
+	struct sgpio_req payload;
+	struct sgpio_ioctl_resp *sgpio_resp;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout;
+	u32 ret = 0, i;
+
+	if (copy_from_user(&buffer, (struct sgpio_buffer *)arg,
+		sizeof(struct sgpio_buffer))) {
+		return ADPT_IOCTL_CALL_FAILED;
+	}
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+	pm8001_ha->ioctl_completion = &completion;
+
+	payload.func_reg_index = cpu_to_le32((req->register_index << 24) |
+			(req->register_type << 16) | (req->function << 8) |
+			SMP_FRAME_REQ);
+	payload.count = req->register_count;
+
+	if (req->function == WRITE_SGPIO_REGISTER) {
+		if (req->register_count > MAX_SGPIO_REQ_PAYLOAD) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		for (i = 0; i < req->register_count; i++)
+			payload.value[i] = req->read_write_data[i];
+	}
+
+	ret = PM8001_CHIP_DISP->sgpio_req(pm8001_ha, &payload);
+	if (ret != 0) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+		goto exit;
+	}
+
+	timeout = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(2000));
+	if (timeout == 0) {
+		ret = ADPT_IOCTL_CALL_TIMEOUT;
+		goto exit;
+	}
+
+	sgpio_resp = &pm8001_ha->sgpio_resp;
+	req->frame_type		= sgpio_resp->func_result & 0xff;
+	req->function		= (sgpio_resp->func_result >> 8) & 0xff;
+	req->function_result	= (sgpio_resp->func_result >> 16) & 0xff;
+	if (req->function == READ_SGPIO_REGISTER) {
+		for (i = 0; i < req->register_count; i++)
+			req->read_write_data[i] = sgpio_resp->value[i];
+	}
+	ret = ADPT_IOCTL_CALL_SUCCESS;
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	buffer.header.return_code = ret;
+	if (copy_to_user((void *)arg, (void *)&buffer,
+			sizeof(struct sgpio_buffer))) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+
+	return ret;
+}
+
 static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
 		unsigned long arg)
 {
@@ -1171,6 +1239,9 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_GPIO:
 		ret = pm8001_gpio_ioctl(pm8001_ha, arg);
 		break;
+	case ADPT_IOCTL_SGPIO:
+		ret = pm8001_sgpio_ioctl(pm8001_ha, arg);
+		break;
 	case ADPT_IOCTL_GET_PHY_PROFILE:
 		ret = pm8001_ioctl_get_phy_profile(pm8001_ha, arg);
 		return ret;
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
index 5be43b2672d4..b1be0bc065d5 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.h
+++ b/drivers/scsi/pm8001/pm8001_ctl.h
@@ -68,6 +68,39 @@
 
 #define MAX_NUM_PHYS			16
 
+/************************************************************
+ * SGPIO Function and Register type
+ ************************************************************/
+#define READ_SGPIO_REGISTER			0x02
+#define WRITE_SGPIO_REGISTER			0x82
+
+#define SMP_FRAME_REQ				0x40
+#define SMP_FRAME_RESP				0x41
+
+#define SGPIO_CONFIG_REG			0x0
+#define SGPIO_DRIVE_BY_DRIVE_RECEIVE_REG	0x1
+#define SGPIO_GENERAL_PURPOSE_RECEIVE_REG	0x2
+#define SGPIO_DRIVE_BY_DRIVE_TRANSMIT_REG	0x3
+#define SGPIO_GENERAL_PURPOSE_TRANSMIT_REG	0x4
+
+/************************************************************
+ * SGPIO Function result
+ ************************************************************/
+#define SGPIO_COMMAND_SUCCESS				0x00
+#define SGPIO_CMD_ERROR_WRONG_FRAME_TYPE		0x01
+#define SGPIO_CMD_ERROR_WRONG_REG_TYPE			0x02
+#define SGPIO_CMD_ERROR_WRONG_REG_INDEX			0x03
+#define SGPIO_CMD_ERROR_WRONG_REG_COUNT			0x04
+#define SGPIO_CMD_ERROR_WRONG_FRAME_REG_TYPE		0x05
+#define SGPIO_CMD_ERROR_WRONG_FUNCTION			0x06
+#define SGPIO_CMD_ERROR_WRONG_FRAME_TYPE_REG_INDEX	0x19
+#define SGPIO_CMD_ERROR_WRONG_FRAME_TYPE_REG_CNT	0x81
+#define SGPIO_CMD_ERROR_WRONG_REG_TYPE_REG_INDEX	0x1A
+#define SGPIO_CMD_ERROR_WRONG_REG_TYPE_REG_COUNT	0x82
+#define SGPIO_CMD_ERROR_WRONG_REG_INDEX_REG_COUNT	0x83
+#define SGPIO_CMD_ERROR_WRONG_FRAME_REG_TYPE_REG_INDEX	0x1D
+#define SGPIO_CMD_ERROR_WRONG_ALL_HEADER_PARAMS		0x9D
+
 struct ioctl_header {
 	u32 io_controller_num;
 	u32 length;
@@ -104,6 +137,39 @@ struct pm8001_gpio {
 	u32	event_falling_edge;
 };
 
+#define MAX_SGPIO_REQ_PAYLOAD	12
+#define MAX_SGPIO_RESP_PAYLOAD	13
+
+struct read_write_req_resp {
+	u8	frame_type;	/* =0x40 */
+	u8	function;	/* 0x02 for read, 0x82 for write */
+	u8	register_type;
+	u8	register_index;
+	u8	register_count;
+	u8	function_result;
+	u32	read_write_data[MAX_SGPIO_RESP_PAYLOAD];
+};
+
+struct sgpio_cfg_0 {
+	u8	reserved;
+	u8	version:4;
+	u8	reserved1:4;
+	u8	gp_register_count:4;
+	u8	cfg_register_count:3;
+	u8	enable:1;
+	u8	supported_drive_cnt;
+};
+
+struct sgpio_cfg_1 {
+	u8	reserved;
+	u8	blink_gen_a:4;
+	u8	blink_gen_b:4;
+	u8	max_act_on:4;
+	u8	forced_act_off:4;
+	u8	stretch_act_on:4;
+	u8	stretch_act_off:4;
+};
+
 struct ioctl_info_buffer {
 	struct ioctl_header	header;
 	struct ioctl_drv_info	information;
@@ -114,6 +180,11 @@ struct gpio_buffer {
 	struct pm8001_gpio	gpio_payload;
 };
 
+struct sgpio_buffer {
+	struct ioctl_header		header;
+	struct read_write_req_resp	sgpio_req;
+};
+
 struct phy_profile {
 	char		phy_id;
 	unsigned int	phys:4;
@@ -143,6 +214,7 @@ struct phy_prof_resp {
 
 #define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
 #define ADPT_IOCTL_GPIO	_IOWR(ADPT_MAGIC_NUMBER, 1, struct  gpio_buffer *)
+#define ADPT_IOCTL_SGPIO _IOWR(ADPT_MAGIC_NUMBER, 2, struct sgpio_buffer *)
 #define ADPT_IOCTL_GET_PHY_PROFILE _IOWR(ADPT_MAGIC_NUMBER, 8, \
 		struct phy_profile*)
 #define ADPT_IOCTL_GET_PHY_ERR_CNT _IOWR(ADPT_MAGIC_NUMBER, 9, \
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 2328ff1349ac..f9395d9fd530 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -3666,6 +3666,49 @@ int pm8001_mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
 	return 0;
 }
 
+/**
+ *pm8001_sgpio_resp - pm8001 SGPIO response
+ *@pm8001_ha: HBA controller information
+ *@piomb: SGPIO payload
+ *Handles SGPIO response from HBA.
+ */
+
+int pm8001_sgpio_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+	u32 func_result;
+	u32 tag, i;
+	u32 value;
+	struct sgpio_ioctl_resp *sgpio_resp;
+	struct sgpio_reg_resp *registerRespPayload =
+		(struct sgpio_reg_resp *)(piomb + 4);
+
+	tag = le32_to_cpu(registerRespPayload->tag);
+	func_result = le32_to_cpu(registerRespPayload->func_result);
+	value = le32_to_cpu(registerRespPayload->value[0]);
+
+	PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+		"SGPIO func result = 0x%x tag %x value %x\n",
+		func_result, tag, value));
+
+	spin_lock(&pm8001_ha->ioctl_lock);
+	if (pm8001_ha->ioctl_completion != NULL) {
+		sgpio_resp = &pm8001_ha->sgpio_resp;
+		sgpio_resp->func_result = func_result;
+		PM8001_MSG_DBG(pm8001_ha,
+			pm8001_printk("SGPIO response value hexdump\n"));
+		for (i = 0; i < MAX_SGPIO_RESP_PAYLOAD; i++) {
+			sgpio_resp->value[i] =
+				le32_to_cpu(registerRespPayload->value[i]);
+			PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+				"value[%d] = %08x\n", i, sgpio_resp->value[i]));
+		}
+		complete(pm8001_ha->ioctl_completion);
+	}
+	spin_unlock(&pm8001_ha->ioctl_lock);
+	pm8001_tag_free(pm8001_ha, tag);
+	return 0;
+}
+
 /**
  * fw_flash_update_resp - Response from FW for flash update command.
  * @pm8001_ha: our hba card information
@@ -4035,7 +4078,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
 static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
 {
 	__le32 pHeader = *(__le32 *)piomb;
-	u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
+	u16 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
 
 	PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:"));
 
@@ -4190,6 +4233,11 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
 		PM8001_MSG_DBG(pm8001_ha,
 			pm8001_printk("OPC_OUB_SAS_RE_INITIALIZE\n"));
 		break;
+	case OPC_OUB_SGPIO_RESP:
+		PM8001_MSG_DBG(pm8001_ha,
+			pm8001_printk("OPC_OUB_SGPIO RESPONSE\n"));
+		pm8001_sgpio_resp(pm8001_ha, piomb);
+		break;
 	default:
 		PM8001_DEVIO_DBG(pm8001_ha,
 			pm8001_printk("Unknown outbound Queue IOMB OPC = %x\n",
@@ -5136,6 +5184,88 @@ pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
 
 }
 
+/**
+ *pm8001_setup_sgpio - Setup SGPIO configuration for SPC/SPCv controllers
+ *pm8001_ha - controller information
+ */
+int pm8001_setup_sgpio(struct pm8001_hba_info *pm8001_ha)
+{
+	struct sgpio_req payload;
+	struct sgpio_cfg_0 *cfg_0;
+	struct sgpio_cfg_1 *cfg_1;
+	int rc, index = 0, i;
+	u32 value = 0;
+	DECLARE_COMPLETION_ONSTACK(completion);
+
+	pm8001_ha->ioctl_completion = &completion;
+	payload.func_reg_index = ((index << 24) | (SGPIO_CONFIG_REG << 16)
+			| (WRITE_SGPIO_REGISTER << 8) | SMP_FRAME_REQ);
+	payload.count = 2;
+
+	cfg_0 = (struct sgpio_cfg_0 *)(&value);
+	cfg_0->enable = 0x1;
+	payload.value[0] = value;
+
+	/*Initialize GPIO CFG 1 register to default as per SFF-8485 spec*/
+	cfg_1 = (struct sgpio_cfg_1 *)(&value);
+	cfg_1->blink_gen_a	= 0;
+	cfg_1->blink_gen_b	= 0;
+	cfg_1->max_act_on	= 0x2;
+	cfg_1->forced_act_off	= 0x1;
+	cfg_1->stretch_act_on	= 0;
+	cfg_1->stretch_act_off	= 0;
+
+	payload.value[1] = value;
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("Setting up sgpio. index %x count %x\n",
+		payload.func_reg_index, payload.count));
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+	pm8001_ha->ioctl_completion = &completion;
+	rc = PM8001_CHIP_DISP->sgpio_req(pm8001_ha, &payload);
+	if (rc) {
+		PM8001_FAIL_DBG(pm8001_ha,
+			pm8001_printk("failed sgpio_req:%d\n", rc));
+		goto exit;
+	}
+	rc = wait_for_completion_timeout(&completion, msecs_to_jiffies(2000));
+	if (rc == 0) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("failed sgpio_req timeout\n"));
+		rc = ADPT_IOCTL_CALL_TIMEOUT;
+		goto exit;
+	}
+	payload.func_reg_index = ((index << 24) |
+			(SGPIO_DRIVE_BY_DRIVE_TRANSMIT_REG << 16) |
+			(WRITE_SGPIO_REGISTER << 8) | SMP_FRAME_REQ);
+	payload.count = pm8001_ha->chip->n_phy/4;
+	value = 0xA0A0A0A0; //Activity=0x5, Locate=0, Error=0
+	for (i = 0; i < payload.count; i++)
+		payload.value[i] = value;
+	reinit_completion(&completion);
+	pm8001_ha->ioctl_completion = &completion;
+	rc = PM8001_CHIP_DISP->sgpio_req(pm8001_ha, &payload);
+	if (rc) {
+		PM8001_FAIL_DBG(pm8001_ha,
+			pm8001_printk("failed sgpio_req:%d\n", rc));
+		goto exit;
+	}
+	rc = wait_for_completion_timeout(&completion, msecs_to_jiffies(2000));
+	if (rc == 0) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("failed sgpio_req timeout\n"));
+		rc = ADPT_IOCTL_CALL_TIMEOUT;
+		goto exit;
+	}
+
+exit:
+	spin_lock(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock(&pm8001_ha->ioctl_lock);
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return rc;
+}
+
 static int
 pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
 {
@@ -5164,6 +5294,45 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
 
 }
 
+/**
+ * pm8001_chip_sgpio_req - support for SGPIO operation
+ * @pm8001_ha: our hba card information.
+ * @ioctl_payload: the payload for the SGPIO operation
+ */
+int pm8001_chip_sgpio_req(struct pm8001_hba_info *pm8001_ha,
+				struct sgpio_req *sgpio_payload)
+{
+	struct sgpio_reg_req payload;
+	struct inbound_queue_table *circularQ;
+	int rc, i;
+	u32 tag;
+	u32 opc = OPC_INB_SGPIO_REG;
+
+	memset(&payload, 0, sizeof(struct sgpio_reg_req));
+	rc = pm8001_tag_alloc(pm8001_ha, &tag);
+	if (rc)
+		return -1;
+
+	circularQ = &pm8001_ha->inbnd_q_tbl[0];
+	payload.tag = cpu_to_le32(tag);
+	payload.func_reg_index = cpu_to_le32(sgpio_payload->func_reg_index);
+	payload.count = cpu_to_le32(sgpio_payload->count);
+
+	for (i = 0; i < sgpio_payload->count; i++)
+		payload.value[i] = cpu_to_le32(sgpio_payload->value[i]);
+
+	PM8001_MSG_DBG(pm8001_ha,
+		pm8001_printk("sgpio operation. tag %x index %x count %x\n",
+		tag, sgpio_payload->func_reg_index, sgpio_payload->count));
+
+	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+			sizeof(payload), 0);
+	if (rc != 0)
+		pm8001_tag_free(pm8001_ha, tag);
+
+	return rc;
+}
+
 const struct pm8001_dispatch pm8001_8001_dispatch = {
 	.name			= "pmc8001",
 	.chip_init		= pm8001_chip_init,
@@ -5191,4 +5360,5 @@ const struct pm8001_dispatch pm8001_8001_dispatch = {
 	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
 	.set_dev_state_req	= pm8001_chip_set_dev_state_req,
 	.sas_re_init_req	= pm8001_chip_sas_re_initialization,
+	.sgpio_req		= pm8001_chip_sgpio_req,
 };
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index 6d91e2446542..aad2322467d2 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -82,6 +82,7 @@
 #define OPC_INB_GET_DEVICE_STATE		43	/* 0x02B */
 #define OPC_INB_SET_DEV_INFO			44	/* 0x02C */
 #define OPC_INB_SAS_RE_INITIALIZE		45	/* 0x02D */
+#define OPC_INB_SGPIO_REG			46	/* 0x02E */
 
 /* for Response Opcode of IOMB */
 #define OPC_OUB_ECHO				1	/* 0x001 */
@@ -120,6 +121,7 @@
 #define OPC_OUB_GET_DEVICE_STATE		39	/* 0x027 */
 #define OPC_OUB_SET_DEV_INFO			40	/* 0x028 */
 #define OPC_OUB_SAS_RE_INITIALIZE		41	/* 0x029 */
+#define OPC_OUB_SGPIO_RESP			2094	/* 0x82E */
 
 /* for phy start*/
 #define SPINHOLD_DISABLE		(0x00 << 14)
@@ -697,6 +699,18 @@ struct set_dev_state_resp {
 	u32		reserved[11];
 } __attribute__((packed, aligned(4)));
 
+struct sgpio_reg_req {
+	__le32		tag;
+	__le32		func_reg_index;
+	__le32		count;
+	__le32		value[12];
+} __packed __aligned(4);
+
+struct sgpio_reg_resp {
+	__le32		tag;
+	__le32		func_result;
+	__le32		value[13];
+} __packed __aligned(4);
 
 #define NDS_BITS 0x0F
 #define PDS_BITS 0xF0
@@ -922,6 +936,9 @@ struct set_dev_state_resp {
 #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */
 #define MAIN_ANALOG_SETUP_OFFSET	0x88/* DWORD 0x22 */
 
+/*FATAL ERROR INTERRUPT bit definition*/
+#define MAIN_CFG_SGPIO_ENABLE		(0x1 << 2)
+
 /* Gereral Status Table offset - byte offset */
 #define GST_GSTLEN_MPIS_OFFSET		0x00
 #define GST_IQ_FREEZE_STATE0_OFFSET	0x04
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 6e2512aa5f6e..c8414f1b9652 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -122,6 +122,7 @@ static struct sas_domain_function_template pm8001_transport_ops = {
 	.lldd_I_T_nexus_reset   = pm8001_I_T_nexus_reset,
 	.lldd_lu_reset		= pm8001_lu_reset,
 	.lldd_query_task	= pm8001_query_task,
+	.lldd_write_gpio	= pm8001_write_sgpio,
 };
 
 /**
@@ -1110,6 +1111,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 	if (pm8001_configure_phy_settings(pm8001_ha))
 		goto err_out_shost;
 
+	pm8001_setup_sgpio(pm8001_ha);
+
 	pm8001_post_sas_ha_init(shost, chip);
 	rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
 	if (rc) {
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index b7cbc312843e..1d03c62d8c99 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -1361,3 +1361,40 @@ int pm8001_clear_task_set(struct domain_device *dev, u8 *lun)
 	return pm8001_issue_ssp_tmf(dev, lun, &tmf_task);
 }
 
+int pm8001_write_sgpio(struct sas_ha_struct *sas_ha, u8 reg_type,
+			u8 reg_index, u8 reg_count, u8 *write_data)
+{
+	struct pm8001_hba_info *pm8001_ha = sas_ha->lldd_ha;
+	struct sgpio_req payload;
+	u32 ret = 0, i, j, value;
+
+	PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+		"reg_type=%x, reg_index:%x, reg_count:%x\n",
+		reg_type, reg_index, reg_count));
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+
+	payload.func_reg_index = cpu_to_le32((reg_index << 24) |
+		(reg_type << 16) | (WRITE_SGPIO_REGISTER << 8) |
+		SMP_FRAME_REQ);
+
+	payload.count = reg_count;
+
+	for (i = 0; i < reg_count; i++) {
+		value = 0;
+		for (j = 0; j < 4; j++) {
+			value |= (u32)(*write_data) << (24-(j*8));
+			write_data++;
+		}
+		payload.value[i] = value;
+		PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+			"payload value: %x\n", payload.value[i]));
+	}
+
+	ret = PM8001_CHIP_DISP->sgpio_req(pm8001_ha, &payload);
+	if (ret != 0)
+		ret = -1;
+
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 7d9920376fb7..4c6c7d86f75e 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -144,6 +144,17 @@ struct gpio_ioctl_resp {
 	u32	gpio_evt_fall;
 };
 
+struct sgpio_req {
+	u32	func_reg_index;
+	u32	count;
+	u32	value[MAX_SGPIO_REQ_PAYLOAD];
+};
+
+struct sgpio_ioctl_resp {
+	u32	func_result;
+	u32	value[MAX_SGPIO_RESP_PAYLOAD];
+};
+
 /* define task management IU */
 struct pm8001_tmf_task {
 	u8	tmf;
@@ -261,6 +272,8 @@ struct pm8001_dispatch {
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
 	int (*gpio_req)(struct pm8001_hba_info *pm8001_ha,
 		struct pm8001_gpio *gpio_payload);
+	int (*sgpio_req)(struct pm8001_hba_info *pm8001_ha,
+		struct sgpio_req *sgpio_payload);
 	int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
 		int phy, int page);
 };
@@ -583,6 +596,7 @@ struct pm8001_hba_info {
 	spinlock_t		ioctl_lock;
 	struct mutex		ioctl_mutex;
 	struct completion	*ioctl_completion;
+	struct			sgpio_ioctl_resp sgpio_resp;
 	struct	phy_prof_resp	phy_profile_resp;
 	u32			reset_in_progress;
 };
@@ -696,6 +710,8 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun);
 int pm8001_I_T_nexus_reset(struct domain_device *dev);
 int pm8001_I_T_nexus_event_handler(struct domain_device *dev);
 int pm8001_query_task(struct sas_task *task);
+int pm8001_write_sgpio(struct sas_ha_struct *sas_ha, u8 reg_type,
+		u8 reg_index, u8 reg_count, u8 *write_data);
 void pm8001_open_reject_retry(
 	struct pm8001_hba_info *pm8001_ha,
 	struct sas_task *task_to_close,
@@ -731,6 +747,8 @@ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha,
 				struct pm8001_device *pm8001_dev,
 				u8 flag, u32 task_tag, u32 cmd_tag);
 int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, u32 device_id);
+int pm8001_chip_sgpio_req(struct pm8001_hba_info *pm8001_ha,
+		struct sgpio_req *sgpio_payload);
 void pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd);
 void pm8001_work_fn(struct work_struct *work);
 int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha,
@@ -752,6 +770,7 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
 							void *piomb);
 int pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha , void *piomb);
 int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb);
+int pm8001_sgpio_resp(struct pm8001_hba_info *pm8001_ha, void *piomb);
 struct sas_task *pm8001_alloc_task(void);
 void pm8001_task_done(struct sas_task *task);
 void pm8001_free_task(struct sas_task *task);
@@ -759,6 +778,7 @@ void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag);
 struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha,
 					u32 device_id);
 int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);
+int pm8001_setup_sgpio(struct pm8001_hba_info *pm8001_ha);
 
 int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
 void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 2cdcb1c64970..e4746fd9c09f 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -4100,6 +4100,11 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			"OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n", opc));
 		ssp_coalesced_comp_resp(pm8001_ha, piomb);
 		break;
+	case OPC_OUB_SGPIO_RESP:
+		PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+			"OPC_OUB_SGPIO RESPONSE opcode: %x\n", opc));
+		pm8001_sgpio_resp(pm8001_ha, piomb);
+		break;
 	default:
 		PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
 			"Unknown outbound Queue IOMB OPC = 0x%x\n", opc));
@@ -5170,5 +5175,6 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
 	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
 	.set_dev_state_req	= pm8001_chip_set_dev_state_req,
 	.gpio_req		= pm80xx_chip_gpio_req,
+	.sgpio_req		= pm8001_chip_sgpio_req,
 	.get_phy_profile_req	= pm8001_chip_get_phy_profile,
 };
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
index fed193df93d6..2d7f67b1cd93 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -1509,6 +1509,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
 #define MAIN_MPI_ILA_RELEASE_TYPE	0xA4 /* DWORD 0x29 */
 #define MAIN_MPI_INACTIVE_FW_VERSION	0XB0 /* DWORD 0x2C */
 
+/*FATAL ERROR INTERRUPT bit definition*/
+#define MAIN_CFG_SGPIO_ENABLE		(0x1 << 2)
+
 /* Gereral Status Table offset - byte offset */
 #define GST_GSTLEN_MPIS_OFFSET		0x00
 #define GST_IQ_FREEZE_STATE0_OFFSET	0x04
-- 
2.16.3




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux