diff options
| author | Sakthivel K <Sakthivel.SaravananKamalRaju@pmcs.com> | 2013-03-19 08:38:40 -0400 |
|---|---|---|
| committer | James Bottomley <JBottomley@Parallels.com> | 2013-05-10 10:47:51 -0400 |
| commit | a6cb3d012b983b350ae3892cff2e692665df0e1e (patch) | |
| tree | e22bce8642adf4f4b5caf08ab0995a131db2e39e | |
| parent | c6b9ef5779c3e1edfa9de949d2a51252bc347663 (diff) | |
[SCSI] pm80xx: thermal, sas controller config and error handling update
Modified thermal configuration to happen after interrupt registration
Added SAS controller configuration during initialization
Added error handling logic to handle I_T_Nexus errors and variants
[jejb: fix up tabs and spaces issues]
Signed-off-by: Anand Kumar S <AnandKumar.Santhanam@pmcs.com>
Acked-by: Jack Wang <jack_wang@usish.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 66 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.c | 150 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.h | 44 |
6 files changed, 249 insertions, 17 deletions
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index dbdd9d386f10..95d04cc78c0b 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c | |||
| @@ -1670,7 +1670,7 @@ void pm8001_work_fn(struct work_struct *work) | |||
| 1670 | } break; | 1670 | } break; |
| 1671 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: | 1671 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
| 1672 | dev = pm8001_dev->sas_device; | 1672 | dev = pm8001_dev->sas_device; |
| 1673 | pm8001_I_T_nexus_reset(dev); | 1673 | pm8001_I_T_nexus_event_handler(dev); |
| 1674 | break; | 1674 | break; |
| 1675 | case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: | 1675 | case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: |
| 1676 | dev = pm8001_dev->sas_device; | 1676 | dev = pm8001_dev->sas_device; |
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 055f7d0e15d8..1c718520036a 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c | |||
| @@ -838,6 +838,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev, | |||
| 838 | if (pm8001_ha->chip_id != chip_8001) { | 838 | if (pm8001_ha->chip_id != chip_8001) { |
| 839 | for (i = 1; i < pm8001_ha->number_of_intr; i++) | 839 | for (i = 1; i < pm8001_ha->number_of_intr; i++) |
| 840 | PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i); | 840 | PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i); |
| 841 | /* setup thermal configuration. */ | ||
| 842 | pm80xx_set_thermal_config(pm8001_ha); | ||
| 841 | } | 843 | } |
| 842 | 844 | ||
| 843 | pm8001_init_sas_add(pm8001_ha); | 845 | pm8001_init_sas_add(pm8001_ha); |
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index c720917d1388..9af95853f840 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c | |||
| @@ -1018,6 +1018,72 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) | |||
| 1018 | return rc; | 1018 | return rc; |
| 1019 | } | 1019 | } |
| 1020 | 1020 | ||
| 1021 | /* | ||
| 1022 | * This function handle the IT_NEXUS_XXX event or completion | ||
| 1023 | * status code for SSP/SATA/SMP I/O request. | ||
| 1024 | */ | ||
| 1025 | int pm8001_I_T_nexus_event_handler(struct domain_device *dev) | ||
| 1026 | { | ||
| 1027 | int rc = TMF_RESP_FUNC_FAILED; | ||
| 1028 | struct pm8001_device *pm8001_dev; | ||
| 1029 | struct pm8001_hba_info *pm8001_ha; | ||
| 1030 | struct sas_phy *phy; | ||
| 1031 | u32 device_id = 0; | ||
| 1032 | |||
| 1033 | if (!dev || !dev->lldd_dev) | ||
| 1034 | return -1; | ||
| 1035 | |||
| 1036 | pm8001_dev = dev->lldd_dev; | ||
| 1037 | device_id = pm8001_dev->device_id; | ||
| 1038 | pm8001_ha = pm8001_find_ha_by_dev(dev); | ||
| 1039 | |||
| 1040 | PM8001_EH_DBG(pm8001_ha, | ||
| 1041 | pm8001_printk("I_T_Nexus handler invoked !!")); | ||
| 1042 | |||
| 1043 | phy = sas_get_local_phy(dev); | ||
| 1044 | |||
| 1045 | if (dev_is_sata(dev)) { | ||
| 1046 | DECLARE_COMPLETION_ONSTACK(completion_setstate); | ||
| 1047 | if (scsi_is_sas_phy_local(phy)) { | ||
| 1048 | rc = 0; | ||
| 1049 | goto out; | ||
| 1050 | } | ||
| 1051 | /* send internal ssp/sata/smp abort command to FW */ | ||
| 1052 | rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , | ||
| 1053 | dev, 1, 0); | ||
| 1054 | msleep(100); | ||
| 1055 | |||
| 1056 | /* deregister the target device */ | ||
| 1057 | pm8001_dev_gone_notify(dev); | ||
| 1058 | msleep(200); | ||
| 1059 | |||
| 1060 | /*send phy reset to hard reset target */ | ||
| 1061 | rc = sas_phy_reset(phy, 1); | ||
| 1062 | msleep(2000); | ||
| 1063 | pm8001_dev->setds_completion = &completion_setstate; | ||
| 1064 | |||
| 1065 | wait_for_completion(&completion_setstate); | ||
| 1066 | } else { | ||
| 1067 | /* send internal ssp/sata/smp abort command to FW */ | ||
| 1068 | rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , | ||
| 1069 | dev, 1, 0); | ||
| 1070 | msleep(100); | ||
| 1071 | |||
| 1072 | /* deregister the target device */ | ||
| 1073 | pm8001_dev_gone_notify(dev); | ||
| 1074 | msleep(200); | ||
| 1075 | |||
| 1076 | /*send phy reset to hard reset target */ | ||
| 1077 | rc = sas_phy_reset(phy, 1); | ||
| 1078 | msleep(2000); | ||
| 1079 | } | ||
| 1080 | PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n", | ||
| 1081 | pm8001_dev->device_id, rc)); | ||
| 1082 | out: | ||
| 1083 | sas_put_local_phy(phy); | ||
| 1084 | |||
| 1085 | return rc; | ||
| 1086 | } | ||
| 1021 | /* mandatory SAM-3, the task reset the specified LUN*/ | 1087 | /* mandatory SAM-3, the task reset the specified LUN*/ |
| 1022 | int pm8001_lu_reset(struct domain_device *dev, u8 *lun) | 1088 | int pm8001_lu_reset(struct domain_device *dev, u8 *lun) |
| 1023 | { | 1089 | { |
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index ab30193f235f..72d46ea398dc 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h | |||
| @@ -563,6 +563,7 @@ int pm8001_dev_found(struct domain_device *dev); | |||
| 563 | void pm8001_dev_gone(struct domain_device *dev); | 563 | void pm8001_dev_gone(struct domain_device *dev); |
| 564 | int pm8001_lu_reset(struct domain_device *dev, u8 *lun); | 564 | int pm8001_lu_reset(struct domain_device *dev, u8 *lun); |
| 565 | int pm8001_I_T_nexus_reset(struct domain_device *dev); | 565 | int pm8001_I_T_nexus_reset(struct domain_device *dev); |
| 566 | int pm8001_I_T_nexus_event_handler(struct domain_device *dev); | ||
| 566 | int pm8001_query_task(struct sas_task *task); | 567 | int pm8001_query_task(struct sas_task *task); |
| 567 | void pm8001_open_reject_retry( | 568 | void pm8001_open_reject_retry( |
| 568 | struct pm8001_hba_info *pm8001_ha, | 569 | struct pm8001_hba_info *pm8001_ha, |
| @@ -625,6 +626,7 @@ void pm8001_free_task(struct sas_task *task); | |||
| 625 | void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag); | 626 | void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag); |
| 626 | struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha, | 627 | struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha, |
| 627 | u32 device_id); | 628 | u32 device_id); |
| 629 | int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha); | ||
| 628 | 630 | ||
| 629 | int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); | 631 | int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); |
| 630 | 632 | ||
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index f0dbe79b049c..670998a8ca79 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c | |||
| @@ -613,7 +613,7 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) | |||
| 613 | * pm80xx_set_thermal_config - support the thermal configuration | 613 | * pm80xx_set_thermal_config - support the thermal configuration |
| 614 | * @pm8001_ha: our hba card information. | 614 | * @pm8001_ha: our hba card information. |
| 615 | */ | 615 | */ |
| 616 | static int | 616 | int |
| 617 | pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) | 617 | pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) |
| 618 | { | 618 | { |
| 619 | struct set_ctrl_cfg_req payload; | 619 | struct set_ctrl_cfg_req payload; |
| @@ -639,6 +639,86 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) | |||
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | /** | 641 | /** |
| 642 | * pm80xx_set_sas_protocol_timer_config - support the SAS Protocol | ||
| 643 | * Timer configuration page | ||
| 644 | * @pm8001_ha: our hba card information. | ||
| 645 | */ | ||
| 646 | static int | ||
| 647 | pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) | ||
| 648 | { | ||
| 649 | struct set_ctrl_cfg_req payload; | ||
| 650 | struct inbound_queue_table *circularQ; | ||
| 651 | SASProtocolTimerConfig_t SASConfigPage; | ||
| 652 | int rc; | ||
| 653 | u32 tag; | ||
| 654 | u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; | ||
| 655 | |||
| 656 | memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); | ||
| 657 | memset(&SASConfigPage, 0, sizeof(SASProtocolTimerConfig_t)); | ||
| 658 | |||
| 659 | rc = pm8001_tag_alloc(pm8001_ha, &tag); | ||
| 660 | |||
| 661 | if (rc) | ||
| 662 | return -1; | ||
| 663 | |||
| 664 | circularQ = &pm8001_ha->inbnd_q_tbl[0]; | ||
| 665 | payload.tag = cpu_to_le32(tag); | ||
| 666 | |||
| 667 | SASConfigPage.pageCode = SAS_PROTOCOL_TIMER_CONFIG_PAGE; | ||
| 668 | SASConfigPage.MST_MSI = 3 << 15; | ||
| 669 | SASConfigPage.STP_SSP_MCT_TMO = (STP_MCT_TMO << 16) | SSP_MCT_TMO; | ||
| 670 | SASConfigPage.STP_FRM_TMO = (SAS_MAX_OPEN_TIME << 24) | | ||
| 671 | (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER; | ||
| 672 | SASConfigPage.STP_IDLE_TMO = STP_IDLE_TIME; | ||
| 673 | |||
| 674 | if (SASConfigPage.STP_IDLE_TMO > 0x3FFFFFF) | ||
