diff options
Diffstat (limited to 'drivers/scsi/mvsas/mv_sas.c')
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.c | 94 |
1 files changed, 79 insertions, 15 deletions
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 7bd0ee3ed2d6..38b47918c047 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c | |||
@@ -203,12 +203,12 @@ int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, | |||
203 | tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id); | 203 | tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id); |
204 | if (tmp & PHY_RST_HARD) | 204 | if (tmp & PHY_RST_HARD) |
205 | break; | 205 | break; |
206 | MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1); | 206 | MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET); |
207 | break; | 207 | break; |
208 | 208 | ||
209 | case PHY_FUNC_LINK_RESET: | 209 | case PHY_FUNC_LINK_RESET: |
210 | MVS_CHIP_DISP->phy_enable(mvi, phy_id); | 210 | MVS_CHIP_DISP->phy_enable(mvi, phy_id); |
211 | MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0); | 211 | MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET); |
212 | break; | 212 | break; |
213 | 213 | ||
214 | case PHY_FUNC_DISABLE: | 214 | case PHY_FUNC_DISABLE: |
@@ -1758,12 +1758,63 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, | |||
1758 | return stat; | 1758 | return stat; |
1759 | } | 1759 | } |
1760 | 1760 | ||
1761 | void mvs_set_sense(u8 *buffer, int len, int d_sense, | ||
1762 | int key, int asc, int ascq) | ||
1763 | { | ||
1764 | memset(buffer, 0, len); | ||
1765 | |||
1766 | if (d_sense) { | ||
1767 | /* Descriptor format */ | ||
1768 | if (len < 4) { | ||
1769 | mv_printk("Length %d of sense buffer too small to " | ||
1770 | "fit sense %x:%x:%x", len, key, asc, ascq); | ||
1771 | } | ||
1772 | |||
1773 | buffer[0] = 0x72; /* Response Code */ | ||
1774 | if (len > 1) | ||
1775 | buffer[1] = key; /* Sense Key */ | ||
1776 | if (len > 2) | ||
1777 | buffer[2] = asc; /* ASC */ | ||
1778 | if (len > 3) | ||
1779 | buffer[3] = ascq; /* ASCQ */ | ||
1780 | } else { | ||
1781 | if (len < 14) { | ||
1782 | mv_printk("Length %d of sense buffer too small to " | ||
1783 | "fit sense %x:%x:%x", len, key, asc, ascq); | ||
1784 | } | ||
1785 | |||
1786 | buffer[0] = 0x70; /* Response Code */ | ||
1787 | if (len > 2) | ||
1788 | buffer[2] = key; /* Sense Key */ | ||
1789 | if (len > 7) | ||
1790 | buffer[7] = 0x0a; /* Additional Sense Length */ | ||
1791 | if (len > 12) | ||
1792 | buffer[12] = asc; /* ASC */ | ||
1793 | if (len > 13) | ||
1794 | buffer[13] = ascq; /* ASCQ */ | ||
1795 | } | ||
1796 | |||
1797 | return; | ||
1798 | } | ||
1799 | |||
1800 | void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu, | ||
1801 | u8 key, u8 asc, u8 asc_q) | ||
1802 | { | ||
1803 | iu->datapres = 2; | ||
1804 | iu->response_data_len = 0; | ||
1805 | iu->sense_data_len = 17; | ||
1806 | iu->status = 02; | ||
1807 | mvs_set_sense(iu->sense_data, 17, 0, | ||
1808 | key, asc, asc_q); | ||
1809 | } | ||
1810 | |||
1761 | static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, | 1811 | static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, |
1762 | u32 slot_idx) | 1812 | u32 slot_idx) |
1763 | { | 1813 | { |
1764 | struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; | 1814 | struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; |
1765 | int stat; | 1815 | int stat; |
1766 | u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); | 1816 | u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); |
1817 | u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1)); | ||
1767 | u32 tfs = 0; | 1818 | u32 tfs = 0; |
1768 | enum mvs_port_type type = PORT_TYPE_SAS; | 1819 | enum mvs_port_type type = PORT_TYPE_SAS; |
1769 | 1820 | ||
@@ -1775,8 +1826,19 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, | |||
1775 | stat = SAM_STAT_CHECK_CONDITION; | 1826 | stat = SAM_STAT_CHECK_CONDITION; |
1776 | switch (task->task_proto) { | 1827 | switch (task->task_proto) { |
1777 | case SAS_PROTOCOL_SSP: | 1828 | case SAS_PROTOCOL_SSP: |
1829 | { | ||
1778 | stat = SAS_ABORTED_TASK; | 1830 | stat = SAS_ABORTED_TASK; |
1831 | if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) { | ||
1832 | struct ssp_response_iu *iu = slot->response + | ||
1833 | sizeof(struct mvs_err_info); | ||
1834 | mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01); | ||
1835 | sas_ssp_task_response(mvi->dev, task, iu); | ||
1836 | stat = SAM_STAT_CHECK_CONDITION; | ||
1837 | } | ||
1838 | if (err_dw1 & bit(31)) | ||
1839 | mv_printk("reuse same slot, retry command.\n"); | ||
1779 | break; | 1840 | break; |
1841 | } | ||
1780 | case SAS_PROTOCOL_SMP: | 1842 | case SAS_PROTOCOL_SMP: |
1781 | stat = SAM_STAT_CHECK_CONDITION; | 1843 | stat = SAM_STAT_CHECK_CONDITION; |
1782 | break; | 1844 | break; |
@@ -1974,13 +2036,13 @@ static void mvs_work_queue(struct work_struct *work) | |||
1974 | struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); | 2036 | struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); |
1975 | struct mvs_info *mvi = mwq->mvi; | 2037 | struct mvs_info *mvi = mwq->mvi; |
1976 | unsigned long flags; | 2038 | unsigned long flags; |
2039 | u32 phy_no = (unsigned long) mwq->data; | ||
2040 | struct sas_ha_struct *sas_ha = mvi->sas; | ||
2041 | struct mvs_phy *phy = &mvi->phy[phy_no]; | ||
2042 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
1977 | 2043 | ||
1978 | spin_lock_irqsave(&mvi->lock, flags); | 2044 | spin_lock_irqsave(&mvi->lock, flags); |
1979 | if (mwq->handler & PHY_PLUG_EVENT) { | 2045 | if (mwq->handler & PHY_PLUG_EVENT) { |
1980 | u32 phy_no = (unsigned long) mwq->data; | ||
1981 | struct sas_ha_struct *sas_ha = mvi->sas; | ||
1982 | struct mvs_phy *phy = &mvi->phy[phy_no]; | ||
1983 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
1984 | 2046 | ||
1985 | if (phy->phy_event & PHY_PLUG_OUT) { | 2047 | if (phy->phy_event & PHY_PLUG_OUT) { |
1986 | u32 tmp; | 2048 | u32 tmp; |
@@ -2002,6 +2064,11 @@ static void mvs_work_queue(struct work_struct *work) | |||
2002 | mv_dprintk("phy%d Attached Device\n", phy_no); | 2064 | mv_dprintk("phy%d Attached Device\n", phy_no); |
2003 | } | 2065 | } |
2004 | } | 2066 | } |
2067 | } else if (mwq->handler & EXP_BRCT_CHG) { | ||
2068 | phy->phy_event &= ~EXP_BRCT_CHG; | ||
2069 | sas_ha->notify_port_event(sas_phy, | ||
2070 | PORTE_BROADCAST_RCVD); | ||
2071 | mv_dprintk("phy%d Got Broadcast Change\n", phy_no); | ||
2005 | } | 2072 | } |
2006 | list_del(&mwq->entry); | 2073 | list_del(&mwq->entry); |
2007 | spin_unlock_irqrestore(&mvi->lock, flags); | 2074 | spin_unlock_irqrestore(&mvi->lock, flags); |
@@ -2037,7 +2104,7 @@ static void mvs_sig_time_out(unsigned long tphy) | |||
2037 | if (&mvi->phy[phy_no] == phy) { | 2104 | if (&mvi->phy[phy_no] == phy) { |
2038 | mv_dprintk("Get signature time out, reset phy %d\n", | 2105 | mv_dprintk("Get signature time out, reset phy %d\n", |
2039 | phy_no+mvi->id*mvi->chip->n_phy); | 2106 | phy_no+mvi->id*mvi->chip->n_phy); |
2040 | MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1); | 2107 | MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET); |
2041 | } | 2108 | } |
2042 | } | 2109 | } |
2043 | } | 2110 | } |
@@ -2045,9 +2112,7 @@ static void mvs_sig_time_out(unsigned long tphy) | |||
2045 | void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) | 2112 | void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) |
2046 | { | 2113 | { |
2047 | u32 tmp; | 2114 | u32 tmp; |
2048 | struct sas_ha_struct *sas_ha = mvi->sas; | ||
2049 | struct mvs_phy *phy = &mvi->phy[phy_no]; | 2115 | struct mvs_phy *phy = &mvi->phy[phy_no]; |
2050 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
2051 | 2116 | ||
2052 | phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no); | 2117 | phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no); |
2053 | mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy, | 2118 | mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy, |
@@ -2086,7 +2151,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) | |||
2086 | phy_no); | 2151 | phy_no); |
2087 | else | 2152 | else |
2088 | MVS_CHIP_DISP->phy_reset(mvi, | 2153 | MVS_CHIP_DISP->phy_reset(mvi, |
2089 | phy_no, 0); | 2154 | phy_no, MVS_SOFT_RESET); |
2090 | return; | 2155 | return; |
2091 | } | 2156 | } |
2092 | } | 2157 | } |
@@ -2118,14 +2183,14 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) | |||
2118 | } | 2183 | } |
2119 | mvs_update_phyinfo(mvi, phy_no, 0); | 2184 | mvs_update_phyinfo(mvi, phy_no, 0); |
2120 | if (phy->phy_type & PORT_TYPE_SAS) { | 2185 | if (phy->phy_type & PORT_TYPE_SAS) { |
2121 | MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2); | 2186 | MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE); |
2122 | mdelay(10); | 2187 | mdelay(10); |
2123 | } | 2188 | } |
2124 | 2189 | ||
2125 | mvs_bytes_dmaed(mvi, phy_no); | 2190 | mvs_bytes_dmaed(mvi, phy_no); |
2126 | /* whether driver is going to handle hot plug */ | 2191 | /* whether driver is going to handle hot plug */ |
2127 | if (phy->phy_event & PHY_PLUG_OUT) { | 2192 | if (phy->phy_event & PHY_PLUG_OUT) { |
2128 | mvs_port_notify_formed(sas_phy, 0); | 2193 | mvs_port_notify_formed(&phy->sas_phy, 0); |
2129 | phy->phy_event &= ~PHY_PLUG_OUT; | 2194 | phy->phy_event &= ~PHY_PLUG_OUT; |
2130 | } | 2195 | } |
2131 | } else { | 2196 | } else { |
@@ -2135,9 +2200,8 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) | |||
2135 | } else if (phy->irq_status & PHYEV_BROAD_CH) { | 2200 | } else if (phy->irq_status & PHYEV_BROAD_CH) { |
2136 | mv_dprintk("port %d broadcast change.\n", | 2201 | mv_dprintk("port %d broadcast change.\n", |
2137 | phy_no + mvi->id*mvi->chip->n_phy); | 2202 | phy_no + mvi->id*mvi->chip->n_phy); |
2138 | /* exception for Samsung disk drive*/ | 2203 | mvs_handle_event(mvi, (void *)(unsigned long)phy_no, |
2139 | mdelay(1000); | 2204 | EXP_BRCT_CHG); |
2140 | sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); | ||
2141 | } | 2205 | } |
2142 | MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); | 2206 | MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); |
2143 | } | 2207 | } |