return rc;
}
+/*
+* This function handle the IT_NEXUS_XXX event or completion
+* status code for SSP/SATA/SMP I/O request.
+*/
+int pm8001_I_T_nexus_event_handler(struct domain_device *dev)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct pm8001_device *pm8001_dev;
+ struct pm8001_hba_info *pm8001_ha;
+ struct sas_phy *phy;
+ u32 device_id = 0;
+
+ if (!dev || !dev->lldd_dev)
+ return -1;
+
+ pm8001_dev = dev->lldd_dev;
+ device_id = pm8001_dev->device_id;
+ pm8001_ha = pm8001_find_ha_by_dev(dev);
+
+ PM8001_EH_DBG(pm8001_ha,
+ pm8001_printk("I_T_Nexus handler invoked !!"));
+
+ phy = sas_get_local_phy(dev);
+
+ if (dev_is_sata(dev)) {
+ DECLARE_COMPLETION_ONSTACK(completion_setstate);
+ if (scsi_is_sas_phy_local(phy)) {
+ rc = 0;
+ goto out;
+ }
+ /* send internal ssp/sata/smp abort command to FW */
+ rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
+ dev, 1, 0);
+ msleep(100);
+
+ /* deregister the target device */
+ pm8001_dev_gone_notify(dev);
+ msleep(200);
+
+ /*send phy reset to hard reset target */
+ rc = sas_phy_reset(phy, 1);
+ msleep(2000);
+ pm8001_dev->setds_completion = &completion_setstate;
+
+ wait_for_completion(&completion_setstate);
+ } else {
+ /* send internal ssp/sata/smp abort command to FW */
+ rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
+ dev, 1, 0);
+ msleep(100);
+
+ /* deregister the target device */
+ pm8001_dev_gone_notify(dev);
+ msleep(200);
+
+ /*send phy reset to hard reset target */
+ rc = sas_phy_reset(phy, 1);
+ msleep(2000);
+ }
+ PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n",
+ pm8001_dev->device_id, rc));
+out:
+ sas_put_local_phy(phy);
+
+ return rc;
+}
/* mandatory SAM-3, the task reset the specified LUN*/
int pm8001_lu_reset(struct domain_device *dev, u8 *lun)
{
* pm80xx_set_thermal_config - support the thermal configuration
* @pm8001_ha: our hba card information.
*/
-static int
+int
pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha)
{
struct set_ctrl_cfg_req payload;
}
+/**
+* pm80xx_set_sas_protocol_timer_config - support the SAS Protocol
+* Timer configuration page
+* @pm8001_ha: our hba card information.
+*/
+static int
+pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha)
+{
+ struct set_ctrl_cfg_req payload;
+ struct inbound_queue_table *circularQ;
+ SASProtocolTimerConfig_t SASConfigPage;
+ int rc;
+ u32 tag;
+ u32 opc = OPC_INB_SET_CONTROLLER_CONFIG;
+
+ memset(&payload, 0, sizeof(struct set_ctrl_cfg_req));
+ memset(&SASConfigPage, 0, sizeof(SASProtocolTimerConfig_t));
+
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+
+ if (rc)
+ return -1;
+
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ payload.tag = cpu_to_le32(tag);
+
+ SASConfigPage.pageCode = SAS_PROTOCOL_TIMER_CONFIG_PAGE;
+ SASConfigPage.MST_MSI = 3 << 15;
+ SASConfigPage.STP_SSP_MCT_TMO = (STP_MCT_TMO << 16) | SSP_MCT_TMO;
+ SASConfigPage.STP_FRM_TMO = (SAS_MAX_OPEN_TIME << 24) |
+ (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER;
+ SASConfigPage.STP_IDLE_TMO = STP_IDLE_TIME;
+
+ if (SASConfigPage.STP_IDLE_TMO > 0x3FFFFFF)
+ SASConfigPage.STP_IDLE_TMO = 0x3FFFFFF;
+
+
+ SASConfigPage.OPNRJT_RTRY_INTVL = (SAS_MFD << 16) |
+ SAS_OPNRJT_RTRY_INTVL;
+ SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = (SAS_DOPNRJT_RTRY_TMO << 16)
+ | SAS_COPNRJT_RTRY_TMO;
+ SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = (SAS_DOPNRJT_RTRY_THR << 16)
+ | SAS_COPNRJT_RTRY_THR;
+ SASConfigPage.MAX_AIP = SAS_MAX_AIP;
+
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.pageCode "
+ "0x%08x\n", SASConfigPage.pageCode));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.MST_MSI "
+ " 0x%08x\n", SASConfigPage.MST_MSI));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.STP_SSP_MCT_TMO "
+ " 0x%08x\n", SASConfigPage.STP_SSP_MCT_TMO));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.STP_FRM_TMO "
+ " 0x%08x\n", SASConfigPage.STP_FRM_TMO));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.STP_IDLE_TMO "
+ " 0x%08x\n", SASConfigPage.STP_IDLE_TMO));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.OPNRJT_RTRY_INTVL "
+ " 0x%08x\n", SASConfigPage.OPNRJT_RTRY_INTVL));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO "
+ " 0x%08x\n", SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR "
+ " 0x%08x\n", SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR));
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk("SASConfigPage.MAX_AIP "
+ " 0x%08x\n", SASConfigPage.MAX_AIP));
+
+ memcpy(&payload.cfg_pg, &SASConfigPage,
+ sizeof(SASProtocolTimerConfig_t));
+
+ rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+
+ return rc;
+}
+
/**
* pm80xx_get_encrypt_info - Check for encryption
* @pm8001_ha: our hba card information.
} else
return -EBUSY;
- /* configure thermal */
- pm80xx_set_thermal_config(pm8001_ha);
-
- PM8001_INIT_DBG(pm8001_ha,
- pm8001_printk("Thermal configuration successful!\n"));
+ /* send SAS protocol timer configuration page to FW */
+ ret = pm80xx_set_sas_protocol_timer_config(pm8001_ha);
/* Check for encryption */
if (pm8001_ha->chip->encrypt) {
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
ts->resp = SAS_TASK_COMPLETE;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
ts->resp = SAS_TASK_COMPLETE;
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
+ case IO_XFER_ERROR_INTERNAL_CRC_ERROR:
+ PM8001_IO_DBG(pm8001_ha,
+ pm8001_printk("IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"));
+ /* TBC: used default set values */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
case IO_XFER_CMD_FRAME_ISSUED:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n"));
ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
ts->resp = SAS_TASK_COMPLETE;
ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
- PM8001_IO_DBG(pm8001_ha,
+ case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
+ PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_DEV_NO_RESPONSE;
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
+ case IO_XFER_ERROR_INTERNAL_CRC_ERROR:
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"));
+ /* TBC: used default set values */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case IO_XFER_DMA_ACTIVATE_TIMEOUT:
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("IO_XFR_DMA_ACTIVATE_TIMEOUT\n"));
+ /* TBC: used default set values */
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_OPEN_TO;
+ break;
default:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("Unknown status 0x%x\n", event));
ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
+ case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
+ case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"));
ts->resp = SAS_TASK_COMPLETE;
case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk("HW_EVENT_PORT_RECOVERY_TIMER_TMO\n"));
+ pm80xx_hw_event_ack_req(pm8001_ha, 0,
+ HW_EVENT_PORT_RECOVERY_TIMER_TMO,
+ port_id, phy_id, 0, 0);
sas_phy_disconnected(sas_phy);
phy->phy_attached = 0;
sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3);
ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7);
memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cdb, 16);
- circularQ = &pm8001_ha->inbnd_q_tbl[inb++];
-
- /* rotate the inb queue */
- inb = inb%PM8001_MAX_SPCV_INB_NUM;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
/* Check if encryption is set */
if (pm8001_ha->chip->encrypt &&
unsigned long flags;
u32 opc = OPC_INB_SATA_HOST_OPSTART;
memset(&sata_cmd, 0, sizeof(sata_cmd));
- circularQ = &pm8001_ha->inbnd_q_tbl[inb++];
-
- /* rotate the inb queue */
- inb = inb%PM8001_MAX_SPCV_INB_NUM;
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
if (task->data_dir == PCI_DMA_NONE) {
ATAP = 0x04; /* no data*/
#define CIPHER_MODE_XTS 0x00000002
#define KEK_MGMT_SUBOP_KEYCARDUPDATE 0x4
+/* SAS protocol timer configuration page */
+#define SAS_PROTOCOL_TIMER_CONFIG_PAGE 0x04
+#define STP_MCT_TMO 32
+#define SSP_MCT_TMO 32
+#define SAS_MAX_OPEN_TIME 5
+#define SMP_MAX_CONN_TIMER 0xFF
+#define STP_FRM_TIMER 0
+#define STP_IDLE_TIME 5 /* 5 us; controller default */
+#define SAS_MFD 0
+#define SAS_OPNRJT_RTRY_INTVL 2
+#define SAS_DOPNRJT_RTRY_TMO 128
+#define SAS_COPNRJT_RTRY_TMO 128
+
+/*
+ Making ORR bigger than IT NEXUS LOSS which is 2000000us = 2 second.
+ Assuming a bigger value 3 second, 3000000/128 = 23437.5 where 128
+ is DOPNRJT_RTRY_TMO
+*/
+#define SAS_DOPNRJT_RTRY_THR 23438
+#define SAS_COPNRJT_RTRY_THR 23438
+#define SAS_MAX_AIP 0x200000
+#define IT_NEXUS_TIMEOUT 0x7D0
+#define PORT_RECOVERY_TIMEOUT ((IT_NEXUS_TIMEOUT/100) + 30)
+
struct mpi_msg_hdr {
__le32 header; /* Bits [11:0] - Message operation code */
/* Bits [15:12] - Message Category */
/* new outbound structure for spcv - ends */
+/* brief data structure for SAS protocol timer configuration page.
+ *
+ */
+struct SASProtocolTimerConfig {
+ __le32 pageCode; /* 0 */
+ __le32 MST_MSI; /* 1 */
+ __le32 STP_SSP_MCT_TMO; /* 2 */
+ __le32 STP_FRM_TMO; /* 3 */
+ __le32 STP_IDLE_TMO; /* 4 */
+ __le32 OPNRJT_RTRY_INTVL; /* 5 */
+ __le32 Data_Cmd_OPNRJT_RTRY_TMO; /* 6 */
+ __le32 Data_Cmd_OPNRJT_RTRY_THR; /* 7 */
+ __le32 MAX_AIP; /* 8 */
+} __attribute__((packed, aligned(4)));
+
+typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
+
#define NDS_BITS 0x0F
#define PDS_BITS 0xF0
#define IO_DS_INVALID 0x49
/* WARNING: the value is not contiguous from here */
#define IO_XFER_ERR_LAST_PIO_DATAIN_CRC_ERR 0x52
-#define IO_XFR_ERROR_INTERNAL_CRC_ERROR 0x54
+#define IO_XFER_DMA_ACTIVATE_TIMEOUT 0x53
+#define IO_XFER_ERROR_INTERNAL_CRC_ERROR 0x54
#define MPI_IO_RQE_BUSY_FULL 0x55
#define IO_XFER_ERR_EOB_DATA_OVERRUN 0x56
#define IO_XFR_ERROR_INVALID_SSP_RSP_FRAME 0x57