All of lore.kernel.org
 help / color / mirror / Atom feed
From: Deepak Ukey <deepak.ukey@microchip.com>
To: <linux-scsi@vger.kernel.org>
Cc: <Vasanthalakshmi.Tharmarajan@microchip.com>,
	<Viswas.G@microchip.com>, <deepak.ukey@microchip.com>,
	<jinpu.wang@profitbricks.com>, <martin.petersen@oracle.com>,
	<dpf@google.com>, <yuuzheng@google.com>, <auradkar@google.com>,
	<vishakhavc@google.com>, <bjashnani@google.com>,
	<radha@google.com>, <akshatzen@google.com>
Subject: [PATCH 07/12] pm80xx : IOCTL functionality to get phy profile.
Date: Tue, 24 Dec 2019 10:11:38 +0530	[thread overview]
Message-ID: <20191224044143.8178-8-deepak.ukey@microchip.com> (raw)
In-Reply-To: <20191224044143.8178-1-deepak.ukey@microchip.com>

From: Viswas G <Viswas.G@microchip.com>

Added the ioctl functionality to collect phy status and phy error.

Signed-off-by: Deepak Ukey <deepak.ukey@microchip.com>
Signed-off-by: Viswas G <Viswas.G@microchip.com>
Signed-off-by: Vishakha Channapattan <vishakhavc@google.com>
Signed-off-by: Bhavesh Jashnani <bjashnani@google.com>
Signed-off-by: Radha Ramachandran <radha@google.com>
Signed-off-by: Akshat Jain <akshatzen@google.com>
Signed-off-by: Yu Zheng <yuuzheng@google.com>
---
 drivers/scsi/pm8001/pm8001_ctl.c | 145 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h |  35 +++++++++-
 drivers/scsi/pm8001/pm8001_sas.h |   9 +++
 drivers/scsi/pm8001/pm80xx_hwi.c |  82 ++++++++++++++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h |   2 +
 5 files changed, 272 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 704c0daa7937..6daae852d5ac 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -41,6 +41,8 @@
 #include <linux/slab.h>
 #include "pm8001_sas.h"
 #include "pm8001_ctl.h"
+#include "pm80xx_hwi.h"
+
 int pm80xx_major = -1;
 
 /* scsi host attributes */
@@ -939,6 +941,143 @@ static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct phy_profile phy_prof[MAX_NUM_PHYS];
+	int nphys;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout = msecs_to_jiffies(2000);
+	u32 ret = 0, i;
+	int page_code = SAS_PHY_GENERAL_STATUS_PAGE;
+
+	if (pm8001_ha->pdev->device == 0x8001 ||
+				pm8001_ha->pdev->device == 0x8081) {
+		return ADPT_IOCTL_CALL_INVALID_DEVICE;
+	}
+
+	if (copy_from_user(&phy_prof[0], (struct phy_profile *)arg,
+				sizeof(struct phy_profile))) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_from_user failed\n"));
+		return ADPT_IOCTL_CALL_FAILED;
+	}
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+	nphys = phy_prof[0].phy_id;
+	if (nphys == -1) {
+		for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+			pm8001_ha->ioctl_completion = &completion;
+			ret = PM8001_CHIP_DISP->get_phy_profile_req(pm8001_ha,
+								i, page_code);
+			if (ret != 0) {
+				PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+					"Get phy profile request failed\n"));
+				ret = ADPT_IOCTL_CALL_FAILED;
+				goto exit;
+			}
+			timeout = wait_for_completion_timeout(&completion,
+					timeout);
+			if (timeout == 0) {
+				ret = ADPT_IOCTL_CALL_FAILED;
+				goto exit;
+			}
+			memcpy((void *)&phy_prof[i],
+				(void *)&pm8001_ha->phy_profile_resp,
+				sizeof(struct phy_profile));
+		}
+
+		if (copy_to_user((void *)arg, (void *)&phy_prof,
+				sizeof(struct phy_profile) * (i))) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_to_user failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	} else {
+		pm8001_ha->ioctl_completion = &completion;
+		ret = PM8001_CHIP_DISP->get_phy_profile_req(pm8001_ha,
+							nphys, page_code);
+		if (ret != 0) {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+				"Get phy profile request failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		timeout = wait_for_completion_timeout(&completion,
+				timeout);
+		if (timeout == 0) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+
+		if (copy_to_user((void *)arg,
+				(void *)&pm8001_ha->phy_profile_resp,
+				sizeof(struct phy_profile))) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_to_user failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	}
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
+
+static int pm8001_ioctl_get_phy_err(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct phy_errcnt phy_err[MAX_NUM_PHYS];
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout = msecs_to_jiffies(2000);
+	u32 ret = 0, i;
+	int page_code = SAS_PHY_ERR_COUNTERS_PAGE;
+	/*6H card does not support phyerr*/
+	if (pm8001_ha->pdev->device == 0x8001 ||
+			pm8001_ha->pdev->device == 0x8081) {
+		return ADPT_IOCTL_CALL_INVALID_DEVICE;
+	}
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+
+	for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+		pm8001_ha->ioctl_completion = &completion;
+		ret = PM8001_CHIP_DISP->get_phy_profile_req(pm8001_ha,
+				i, page_code);
+		if (ret != 0) {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+				"Get phy profile request failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		timeout = wait_for_completion_timeout(&completion,
+				timeout);
+		if (timeout == 0) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		memcpy((void *)&phy_err[i],
+			(void *)&pm8001_ha->phy_profile_resp,
+			sizeof(struct phy_errcnt));
+	}
+
+	if (copy_to_user((void *)arg, (void *)&phy_err,
+			sizeof(struct phy_errcnt) * (i))) {
+		PM8001_FAIL_DBG(pm8001_ha,
+			pm8001_printk("copy_to_user failed\n"));
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
+
 /**
  *	pm8001_ioctl - pm8001 configuration request
  *	@inode: inode of device
@@ -962,6 +1101,12 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_INFO:
 		ret = pm8001_info_ioctl(pm8001_ha, arg);
 		break;
+	case ADPT_IOCTL_GET_PHY_PROFILE:
+		ret = pm8001_ioctl_get_phy_profile(pm8001_ha, arg);
+		return ret;
+	case ADPT_IOCTL_GET_PHY_ERR_CNT:
+		ret = pm8001_ioctl_get_phy_err(pm8001_ha, arg);
+		break;
 	default:
 		ret = ADPT_IOCTL_CALL_INVALID_CODE;
 	}
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
index f0f8b1deae27..686ad69f0e0c 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.h
+++ b/drivers/scsi/pm8001/pm8001_ctl.h
@@ -63,6 +63,9 @@
 #define ADPT_IOCTL_CALL_SUCCESS		0x00
 #define ADPT_IOCTL_CALL_FAILED		0x01
 #define ADPT_IOCTL_CALL_INVALID_CODE	0x03
+#define ADPT_IOCTL_CALL_INVALID_DEVICE	0x04
+
+#define MAX_NUM_PHYS			16
 
 struct ioctl_header {
 	u32 io_controller_num;
@@ -88,8 +91,38 @@ struct ioctl_info_buffer {
 	struct ioctl_drv_info	information;
 };
 
-#define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
+struct phy_profile {
+	char		phy_id;
+	unsigned int	phys:4;
+	unsigned int	nlr:4;
+	unsigned int	plr:4;
+	unsigned int	reserved1:12;
+	unsigned char	port_id;
+	unsigned int	prts:4;
+	unsigned int	reserved2:20;
+} __packed;
+
+struct phy_errcnt {
+	unsigned int  InvalidDword;
+	unsigned int  runningDisparityError;
+	unsigned int  codeViolation;
+	unsigned int  LossOfSyncDW;
+	unsigned int  phyResetProblem;
+	unsigned int  inboundCRCError;
+};
 
+struct phy_prof_resp {
+	union {
+		struct phy_profile status;
+		struct phy_errcnt errcnt;
+	} phy;
+};
+
+#define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_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, \
+		struct phy_err*)
 #define ADPT_MAGIC_NUMBER	'm'
 
 #endif /* PM8001_CTL_H_INCLUDED */
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 479aac34d7cc..99920d53ac09 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -56,6 +56,7 @@
 #include <scsi/sas_ata.h>
 #include <linux/atomic.h>
 #include "pm8001_defs.h"
+#include "pm8001_ctl.h"
 
 #define DRV_NAME		"pm80xx"
 #define DRV_VERSION		"0.1.39"
@@ -246,6 +247,8 @@ struct pm8001_dispatch {
 	int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
 		u32 state);
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+	int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
+		int phy, int page);
 };
 
 struct pm8001_chip_info {
@@ -560,6 +563,12 @@ struct pm8001_hba_info {
 	bool			controller_fatal_error;
 	const struct firmware 	*fw_image;
 	struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];
+	spinlock_t		ioctl_lock;
+	struct mutex		ioctl_mutex;
+	struct completion	*ioctl_completion;
+	struct timer_list	ioctl_timer;
+	u32			ioctl_timer_expired;
+	struct	phy_prof_resp	phy_profile_resp;
 	u32			reset_in_progress;
 };
 
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 37b82d7aa3d7..7f2b7b1d4110 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -3688,9 +3688,62 @@ static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha,
 static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
 			void *piomb)
 {
+	u32 tag, page_code;
+	struct phy_profile *phy_profile, *phy_prof;
+	struct phy_errcnt *phy_err, *phy_err_cnt;
+	struct get_phy_profile_resp *pPayload =
+		(struct get_phy_profile_resp *)(piomb + 4);
+	u32 status = le32_to_cpu(pPayload->status);
+
+	page_code = (u8)((pPayload->ppc_phyid & 0xFF00) >> 8);
+
 	PM8001_MSG_DBG(pm8001_ha,
 			pm8001_printk(" pm80xx_addition_functionality\n"));
 
+	if (status) {
+		/* status is FAILED */
+		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+			"mpiGetPhyProfileReq failed  with status 0x%08x\n",
+			status));
+	}
+
+	tag = le32_to_cpu(pPayload->tag);
+
+	spin_lock(&pm8001_ha->ioctl_lock);
+	if (pm8001_ha->ioctl_completion != NULL) {
+		if (status) {
+			/* signal fail status */
+			memset(&pm8001_ha->phy_profile_resp, 0xff,
+				sizeof(pm8001_ha->phy_profile_resp));
+		} else if (page_code == SAS_PHY_ERR_COUNTERS_PAGE) {
+			phy_err =
+			(struct phy_errcnt *)&pm8001_ha->phy_profile_resp;
+			phy_err_cnt =
+				(struct phy_errcnt *)pPayload->ppc_specific_rsp;
+			phy_err->InvalidDword =
+				le32_to_cpu(phy_err_cnt->InvalidDword);
+			phy_err->runningDisparityError =
+				le32_to_cpu(phy_err_cnt->runningDisparityError);
+			phy_err->LossOfSyncDW =
+				le32_to_cpu(phy_err_cnt->LossOfSyncDW);
+			phy_err->phyResetProblem =
+				le32_to_cpu(phy_err_cnt->phyResetProblem);
+		} else if (page_code == SAS_PHY_GENERAL_STATUS_PAGE) {
+			phy_profile =
+			(struct phy_profile *)&pm8001_ha->phy_profile_resp;
+			phy_prof =
+			(struct phy_profile *)pPayload->ppc_specific_rsp;
+			phy_profile->phy_id = le32_to_cpu(phy_prof->phy_id);
+			phy_profile->phys = le32_to_cpu(phy_prof->phys);
+			phy_profile->plr = le32_to_cpu(phy_prof->plr);
+			phy_profile->nlr = le32_to_cpu(phy_prof->nlr);
+			phy_profile->port_id = le32_to_cpu(phy_prof->port_id);
+			phy_profile->prts = le32_to_cpu(phy_prof->prts);
+		}
+		complete(pm8001_ha->ioctl_completion);
+	}
+	spin_unlock(&pm8001_ha->ioctl_lock);
+	pm8001_tag_free(pm8001_ha, tag);
 	return 0;
 }
 
@@ -4883,6 +4936,34 @@ pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
 	return IRQ_HANDLED;
 }
 
+int pm8001_chip_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
+		int phy_id, int page_code)
+{
+
+	u32 tag;
+	struct get_phy_profile_req payload;
+	struct inbound_queue_table *circularQ;
+	int rc, ppc_phyid;
+	u32 opc = OPC_INB_GET_PHY_PROFILE;
+
+	memset(&payload, 0, sizeof(payload));
+
+	rc = pm8001_tag_alloc(pm8001_ha, &tag);
+	if (rc)
+		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Invalid tag\n"));
+
+	circularQ = &pm8001_ha->inbnd_q_tbl[0];
+
+	payload.tag = cpu_to_le32(tag);
+	ppc_phyid = (page_code & 0xFF)  << 8 | (phy_id & 0xFF);
+	payload.ppc_phyid = cpu_to_le32(ppc_phyid);
+
+	pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
+			sizeof(payload), 0);
+
+	return rc;
+}
+
 void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
 	u32 operation, u32 phyid, u32 length, u32 *buf)
 {
@@ -4983,4 +5064,5 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
 	.set_nvmd_req		= pm8001_chip_set_nvmd_req,
 	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
 	.set_dev_state_req	= pm8001_chip_set_dev_state_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 701951a0f715..b5119c5479da 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -175,7 +175,9 @@
 #define PHY_STOP_ERR_DEVICE_ATTACHED	0x1046
 
 /* phy_profile */
+#define SAS_PHY_ERR_COUNTERS_PAGE	0x01
 #define SAS_PHY_ANALOG_SETTINGS_PAGE	0x04
+#define SAS_PHY_GENERAL_STATUS_PAGE	0x05
 #define PHY_DWORD_LENGTH		0xC
 
 /* Thermal related */
-- 
2.16.3


  parent reply	other threads:[~2019-12-24  4:41 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-24  4:41 [PATCH 00/12] pm80xx : Updates for the driver version 0.1.39 Deepak Ukey
2019-12-24  4:41 ` [PATCH 01/12] pm80xx : Increase request sg length Deepak Ukey
2019-12-25 15:57   ` kbuild test robot
2019-12-25 15:57     ` kbuild test robot
2019-12-24  4:41 ` [PATCH 02/12] pm80xx : Deal with kexec reboots Deepak Ukey
2020-01-02 11:52   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 03/12] pm80xx : Free the tag when mpi_set_phy_profile_resp is received Deepak Ukey
2020-01-02 11:55   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 04/12] pm80xx : Cleanup initialization loading fail path Deepak Ukey
2020-01-02 11:58   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 05/12] pm80xx : Support for char device Deepak Ukey
2020-01-02 12:03   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 06/12] pm80xx : sysfs attribute for number of phys Deepak Ukey
2020-01-02 12:07   ` Jinpu Wang
2020-01-02 12:33     ` John Garry
2020-01-02 16:38       ` Viswas.G
2020-01-13  9:26         ` Deepak.Ukey
2020-01-13  9:39           ` Jinpu Wang
2019-12-24  4:41 ` Deepak Ukey [this message]
2020-01-02 12:10   ` [PATCH 07/12] pm80xx : IOCTL functionality to get phy profile Jinpu Wang
2020-01-02 16:42     ` Viswas.G
2019-12-24  4:41 ` [PATCH 08/12] pm80xx : IOCTL functionality for GPIO Deepak Ukey
2020-01-06 16:25   ` Jinpu Wang
2020-01-06 16:39     ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 09/12] pm80xx : IOCTL functionality for SGPIO Deepak Ukey
2019-12-30  2:47   ` Nathan Chancellor
2020-01-06 16:30   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 10/12] pm80xx : sysfs attribute for non fatal dump Deepak Ukey
2020-01-06 16:34   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 11/12] pm80xx : Introduce read and write length for IOCTL payload structure Deepak Ukey
2020-01-06 16:35   ` Jinpu Wang
2019-12-24  4:41 ` [PATCH 12/12] pm80xx : IOCTL functionality for TWI device Deepak Ukey
2020-01-02 12:20   ` Jinpu Wang
2020-01-02 16:41     ` Viswas.G

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191224044143.8178-8-deepak.ukey@microchip.com \
    --to=deepak.ukey@microchip.com \
    --cc=Vasanthalakshmi.Tharmarajan@microchip.com \
    --cc=Viswas.G@microchip.com \
    --cc=akshatzen@google.com \
    --cc=auradkar@google.com \
    --cc=bjashnani@google.com \
    --cc=dpf@google.com \
    --cc=jinpu.wang@profitbricks.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=radha@google.com \
    --cc=vishakhavc@google.com \
    --cc=yuuzheng@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.