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 09/12] pm80xx : IOCTL functionality for SGPIO.
Date: Tue, 24 Dec 2019 10:11:40 +0530 [thread overview]
Message-ID: <20191224044143.8178-10-deepak.ukey@microchip.com> (raw)
In-Reply-To: <20191224044143.8178-1-deepak.ukey@microchip.com>
From: Deepak Ukey <Deepak.Ukey@microchip.com>
Added the IOCTL functionality for SGPIO.
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 | 73 ++++++++++++++++
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, 402 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 8292074c1e6f..3e59b2a7185a 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -1009,6 +1009,76 @@ 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;
+ }
+ if (timeout < 2000)
+ timeout = 2000;
+
+ timeout = wait_for_completion_timeout(&completion,
+ msecs_to_jiffies(timeout));
+ 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)
{
@@ -1172,6 +1242,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 8e442214c954..f95f4d714983 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);
};
@@ -585,6 +598,7 @@ struct pm8001_hba_info {
struct completion *ioctl_completion;
struct timer_list ioctl_timer;
u32 ioctl_timer_expired;
+ struct sgpio_ioctl_resp sgpio_resp;
struct phy_prof_resp phy_profile_resp;
u32 reset_in_progress;
};
@@ -698,6 +712,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,
@@ -733,6 +749,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,
@@ -754,6 +772,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);
@@ -761,6 +780,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 10a922e5a478..bbcdcff5d25b 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
next prev 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 ` [PATCH 07/12] pm80xx : IOCTL functionality to get phy profile Deepak Ukey
2020-01-02 12:10 ` 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 ` Deepak Ukey [this message]
2019-12-30 2:47 ` [PATCH 09/12] pm80xx : IOCTL functionality for SGPIO 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-10-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.