diff options
Diffstat (limited to 'drivers/scsi/pm8001')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_defs.h | 4 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 4 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 5 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 19 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.h | 12 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.c | 111 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.h | 5 |
7 files changed, 120 insertions, 40 deletions
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 74a4bb9af07b..f14ec6e042b9 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -49,13 +49,15 @@ enum chip_flavors { chip_8019, chip_8074, chip_8076, - chip_8077 + chip_8077, + chip_8006, }; enum phy_speed { PHY_SPEED_15 = 0x01, PHY_SPEED_30 = 0x02, PHY_SPEED_60 = 0x04, + PHY_SPEED_120 = 0x08, }; enum data_direction { diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 96dcc097a463..39306b1e704c 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3263,6 +3263,10 @@ void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate) struct sas_phy *sas_phy = phy->sas_phy.phy; switch (link_rate) { + case PHY_SPEED_120: + phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS; + phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_12_0_GBPS; + break; case PHY_SPEED_60: phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS; phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index a132f2664d2f..5c0356fb6310 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -57,6 +57,7 @@ static const struct pm8001_chip_info pm8001_chips[] = { [chip_8074] = {0, 8, &pm8001_80xx_dispatch,}, [chip_8076] = {0, 16, &pm8001_80xx_dispatch,}, [chip_8077] = {0, 16, &pm8001_80xx_dispatch,}, + [chip_8006] = {0, 16, &pm8001_80xx_dispatch,}, }; static int pm8001_id; @@ -1107,6 +1108,8 @@ err_out_enable: */ static struct pci_device_id pm8001_pci_table[] = { { PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 }, + { PCI_VDEVICE(PMC_Sierra, 0x8006), chip_8006 }, + { PCI_VDEVICE(ADAPTEC2, 0x8006), chip_8006 }, { PCI_VDEVICE(ATTO, 0x0042), chip_8001 }, /* Support for SPC/SPCv/SPCve controllers */ { PCI_VDEVICE(ADAPTEC2, 0x8001), chip_8001 }, @@ -1217,7 +1220,7 @@ MODULE_AUTHOR("Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>"); MODULE_AUTHOR("Sangeetha Gnanasekaran <Sangeetha.Gnanasekaran@pmcs.com>"); MODULE_AUTHOR("Nikith Ganigarakoppal <Nikith.Ganigarakoppal@pmcs.com>"); MODULE_DESCRIPTION( - "PMC-Sierra PM8001/8081/8088/8089/8074/8076/8077 " + "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077 " "SAS/SATA controller driver"); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index b93f289b42b3..949198c01ced 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -790,6 +790,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; + ccb->n_elem = 0; res = PM8001_CHIP_DISP->task_abort(pm8001_ha, pm8001_dev, flag, task_tag, ccb_tag); @@ -975,19 +976,27 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) 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; } rc = sas_phy_reset(phy, 1); + if (rc) { + PM8001_EH_DBG(pm8001_ha, + pm8001_printk("phy reset failed for device %x\n" + "with rc %d\n", pm8001_dev->device_id, rc)); + rc = TMF_RESP_FUNC_FAILED; + goto out; + } msleep(2000); rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , dev, 1, 0); - pm8001_dev->setds_completion = &completion_setstate; - rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, - pm8001_dev, 0x01); - wait_for_completion(&completion_setstate); + if (rc) { + PM8001_EH_DBG(pm8001_ha, + pm8001_printk("task abort failed %x\n" + "with rc %d\n", pm8001_dev->device_id, rc)); + rc = TMF_RESP_FUNC_FAILED; + } } else { rc = sas_phy_reset(phy, 1); msleep(2000); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 8dd8b7840f04..e2e97db38ae8 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -58,7 +58,7 @@ #include "pm8001_defs.h" #define DRV_NAME "pm80xx" -#define DRV_VERSION "0.1.37" +#define DRV_VERSION "0.1.38" #define PM8001_FAIL_LOGGING 0x01 /* Error message logging */ #define PM8001_INIT_LOGGING 0x02 /* driver init logging */ #define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */ @@ -241,7 +241,7 @@ struct pm8001_chip_info { struct pm8001_port { struct asd_sas_port sas_port; u8 port_attached; - u8 wide_port_phymap; + u16 wide_port_phymap; u8 port_state; struct list_head list; }; @@ -569,6 +569,14 @@ struct pm8001_fw_image_header { #define NCQ_READ_LOG_FLAG 0x80000000 #define NCQ_ABORT_ALL_FLAG 0x40000000 #define NCQ_2ND_RLE_FLAG 0x20000000 + +/* Device states */ +#define DS_OPERATIONAL 0x01 +#define DS_PORT_IN_RESET 0x02 +#define DS_IN_RECOVERY 0x03 +#define DS_IN_ERROR 0x04 +#define DS_NON_OPERATIONAL 0x07 + /** * brief param structure for firmware flash update. */ diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 05cce463ab01..0e1628f2018e 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -309,6 +309,9 @@ static void read_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_mr32(address, MAIN_INT_VECTOR_TABLE_OFFSET); pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset = pm8001_mr32(address, MAIN_SAS_PHY_ATTR_TABLE_OFFSET); + /* read port recover and reset timeout */ + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer = + pm8001_mr32(address, MAIN_PORT_RECOVERY_TIMER); } /** @@ -585,6 +588,12 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); pm8001_mw32(address, MAIN_INT_REASSERTION_DELAY, pm8001_ha->main_cfg_tbl.pm80xx_tbl.interrupt_reassertion_delay); + + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 0xffff0000; + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= + PORT_RECOVERY_TIMEOUT; + pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); } /** @@ -843,6 +852,7 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) int rc; u32 tag; u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; + u32 page_code; memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); rc = pm8001_tag_alloc(pm8001_ha, &tag); @@ -851,8 +861,14 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) circularQ = &pm8001_ha->inbnd_q_tbl[0]; payload.tag = cpu_to_le32(tag); + + if (IS_SPCV_12G(pm8001_ha->pdev)) + page_code = THERMAL_PAGE_CODE_7H; + else + page_code = THERMAL_PAGE_CODE_8H; + payload.cfg_pg[0] = (THERMAL_LOG_ENABLE << 9) | - (THERMAL_ENABLE << 8) | THERMAL_OP_CODE; + (THERMAL_ENABLE << 8) | page_code; payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); @@ -1593,6 +1609,13 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; + case IO_XFER_ERROR_INVALID_SSP_RSP_FRAME: + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n")); + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); @@ -2829,6 +2852,32 @@ static void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, u32 phyId, u32 phy_op); +static void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha, + void *piomb) +{ + struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4); + u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); + u8 phy_id = (u8)((phyid_npip_portstate & 0xFF0000) >> 16); + u32 lr_status_evt_portid = + le32_to_cpu(pPayload->lr_status_evt_portid); + u8 deviceType = pPayload->sas_identify.dev_type; + u8 link_rate = (u8)((lr_status_evt_portid & 0xF0000000) >> 28); + struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; + u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); + struct pm8001_port *port = &pm8001_ha->port[port_id]; + + if (deviceType == SAS_END_DEVICE) { + pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, + PHY_NOTIFY_ENABLE_SPINUP); + } + + port->wide_port_phymap |= (1U << phy_id); + pm8001_get_lrate_mode(phy, link_rate); + phy->sas_phy.oob_mode = SAS_OOB_MODE; + phy->phy_state = PHY_STATE_LINK_UP_SPCV; + phy->phy_attached = 1; +} + /** * hw_event_sas_phy_up -FW tells me a SAS phy up event. * @pm8001_ha: our hba card information @@ -2856,6 +2905,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) unsigned long flags; u8 deviceType = pPayload->sas_identify.dev_type; port->port_state = portstate; + port->wide_port_phymap |= (1U << phy_id); phy->phy_state = PHY_STATE_LINK_UP_SPCV; PM8001_MSG_DBG(pm8001_ha, pm8001_printk( "portid:%d; phyid:%d; linkrate:%d; " @@ -2981,7 +3031,6 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_port *port = &pm8001_ha->port[port_id]; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; port->port_state = portstate; - phy->phy_type = 0; phy->identify.device_type = 0; phy->phy_attached = 0; memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE); @@ -2993,9 +3042,13 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk(" PortInvalid portID %d\n", port_id)); PM8001_MSG_DBG(pm8001_ha, pm8001_printk(" Last phy Down and port invalid\n")); - port->port_attached = 0; - pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, - port_id, phy_id, 0, 0); + if (phy->phy_type & PORT_TYPE_SATA) { + phy->phy_type = 0; + port->port_attached = 0; + pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, + port_id, phy_id, 0, 0); + } + sas_phy_disconnected(&phy->sas_phy); break; case PORT_IN_RESET: PM8001_MSG_DBG(pm8001_ha, @@ -3003,22 +3056,26 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) break; case PORT_NOT_ESTABLISHED: PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n")); + pm8001_printk(" Phy Down and PORT_NOT_ESTABLISHED\n")); port->port_attached = 0; break; case PORT_LOSTCOMM: PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_LOSTCOMM\n")); + pm8001_printk(" Phy Down and PORT_LOSTCOMM\n")); PM8001_MSG_DBG(pm8001_ha, pm8001_printk(" Last phy Down and port invalid\n")); - port->port_attached = 0; - pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, - port_id, phy_id, 0, 0); + if (phy->phy_type & PORT_TYPE_SATA) { + port->port_attached = 0; + phy->phy_type = 0; + pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, + port_id, phy_id, 0, 0); + } + sas_phy_disconnected(&phy->sas_phy); break; default: port->port_attached = 0; PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and(default) = 0x%x\n", + pm8001_printk(" Phy Down and(default) = 0x%x\n", portstate)); break; @@ -3084,7 +3141,7 @@ static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) */ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { - unsigned long flags; + unsigned long flags, i; struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4); u32 lr_status_evt_portid = @@ -3097,9 +3154,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) (u16)((lr_status_evt_portid & 0x00FFFF00) >> 8); u8 status = (u8)((lr_status_evt_portid & 0x0F000000) >> 24); - struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; + struct pm8001_port *port = &pm8001_ha->port[port_id]; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; PM8001_MSG_DBG(pm8001_ha, pm8001_printk("portid:%d phyid:%d event:0x%x status:0x%x\n", @@ -3125,7 +3182,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) case HW_EVENT_PHY_DOWN: PM8001_MSG_DBG(pm8001_ha, pm8001_printk("HW_EVENT_PHY_DOWN\n")); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); + if (phy->phy_type & PORT_TYPE_SATA) + sas_ha->notify_phy_event(&phy->sas_phy, + PHYE_LOSS_OF_SIGNAL); phy->phy_attached = 0; phy->phy_state = 0; hw_event_phy_down(pm8001_ha, piomb); @@ -3169,9 +3228,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("HW_EVENT_LINK_ERR_INVALID_DWORD\n")); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_INVALID_DWORD, 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); break; case HW_EVENT_LINK_ERR_DISPARITY_ERROR: PM8001_MSG_DBG(pm8001_ha, @@ -3179,9 +3235,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_DISPARITY_ERROR, 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); break; case HW_EVENT_LINK_ERR_CODE_VIOLATION: PM8001_MSG_DBG(pm8001_ha, @@ -3189,9 +3242,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_CODE_VIOLATION, 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); break; case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: PM8001_MSG_DBG(pm8001_ha, pm8001_printk( @@ -3199,9 +3249,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, 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); break; case HW_EVENT_MALFUNCTION: PM8001_MSG_DBG(pm8001_ha, @@ -3257,13 +3304,19 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) 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); + for (i = 0; i < pm8001_ha->chip->n_phy; i++) { + if (port->wide_port_phymap & (1 << i)) { + phy = &pm8001_ha->phy[i]; + sas_ha->notify_phy_event(&phy->sas_phy, + PHYE_LOSS_OF_SIGNAL); + port->wide_port_phymap &= ~(1 << i); + } + } break; case HW_EVENT_PORT_RECOVER: PM8001_MSG_DBG(pm8001_ha, pm8001_printk("HW_EVENT_PORT_RECOVER\n")); + hw_event_port_recover(pm8001_ha, piomb); break; case HW_EVENT_PORT_RESET_COMPLETE: PM8001_MSG_DBG(pm8001_ha, diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 9970a385795d..7a443bad6163 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -177,7 +177,8 @@ /* Thermal related */ #define THERMAL_ENABLE 0x1 #define THERMAL_LOG_ENABLE 0x1 -#define THERMAL_OP_CODE 0x6 +#define THERMAL_PAGE_CODE_7H 0x6 +#define THERMAL_PAGE_CODE_8H 0x7 #define LTEMPHIL 70 #define RTEMPHIL 100 @@ -1174,7 +1175,7 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; #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 +#define IO_XFER_ERROR_INVALID_SSP_RSP_FRAME 0x57 #define IO_OPEN_CNX_ERROR_OPEN_PREEMPTED 0x58 #define MPI_ERR_IO_RESOURCE_UNAVAILABLE 0x1004 |