[PATCH V2 07/13] pm80xx : IOCTL functionality to get phy status.

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

 



From: Viswas G <Viswas.G@xxxxxxxxxxxxx>

Added the IOCTL functionality for phy status so that management
utility can get the information like phy id, phy status, port id
and port status from driver using get phy profile command.

Signed-off-by: Deepak Ukey <deepak.ukey@xxxxxxxxxxxxx>
Signed-off-by: Viswas G <Viswas.G@xxxxxxxxxxxxx>
Signed-off-by: Radha Ramachandran <radha@xxxxxxxxxx>
---
 drivers/scsi/pm8001/pm8001_ctl.c | 90 ++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h | 23 +++++++++-
 drivers/scsi/pm8001/pm8001_sas.h |  7 ++++
 drivers/scsi/pm8001/pm80xx_hwi.c | 68 ++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h |  1 +
 5 files changed, 188 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 8091e78a04b0..eb64566b2274 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,91 @@ 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;
+}
+
 /**
  *	pm8001_ioctl - pm8001 configuration request
  *	@inode: inode of device
@@ -962,6 +1049,9 @@ 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;
 	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..226fab82845f 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,26 @@ 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_prof_resp {
+	union {
+		struct phy_profile status;
+	} 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_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..87d676810a18 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,10 @@ 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	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..0a36c5d5e2c2 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -3688,9 +3688,48 @@ 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 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_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 +4922,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 +5050,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..230877caeed4 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -176,6 +176,7 @@
 
 /* phy_profile */
 #define SAS_PHY_ANALOG_SETTINGS_PAGE	0x04
+#define SAS_PHY_GENERAL_STATUS_PAGE	0x05
 #define PHY_DWORD_LENGTH		0xC
 
 /* Thermal related */
-- 
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