2007-10-26 04:58:22 +04:00
/*
2009-05-09 01:46:40 +04:00
* Marvell 88 SE64xx / 88 SE94xx main function
*
* Copyright 2007 Red Hat , Inc .
* Copyright 2008 Marvell . < kewei @ marvell . com >
2011-04-26 17:36:51 +04:00
* Copyright 2009 - 2011 Marvell . < yuxiangl @ marvell . com >
2009-05-09 01:46:40 +04:00
*
* This file is licensed under GPLv2 .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; version 2 of the
* License .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA
*/
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
# include "mv_sas.h"
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
static int mvs_find_tag ( struct mvs_info * mvi , struct sas_task * task , u32 * tag )
{
if ( task - > lldd_task ) {
struct mvs_slot_info * slot ;
2009-05-15 04:41:21 +04:00
slot = task - > lldd_task ;
2009-05-09 01:46:40 +04:00
* tag = slot - > slot_tag ;
2009-05-09 01:44:01 +04:00
return 1 ;
}
return 0 ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
void mvs_tag_clear ( struct mvs_info * mvi , u32 tag )
2009-05-09 01:44:01 +04:00
{
[SCSI] mvsas: Remove unused macros, variables and functions
Remove unused macros: VSR_PHY_VS0, VSR_PHY_VS1, MVS_SLOTS,
MVS_CAN_QUEUE, MVS_MSI, SG_MX, _MV_DUMP, MV_DISABLE_NCQ
Remove unused variables for mvs_info: irq, exp_req, cmd_size
Remove unused functions: mvs_get_sas_addr, mvs_hexdump,
mvs_hba_sb_dump, mvs_hab_memory_dump, mvs_hba_cq_dump
Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2011-05-24 18:35:09 +04:00
void * bitmap = mvi - > tags ;
2009-05-09 01:44:01 +04:00
clear_bit ( tag , bitmap ) ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
void mvs_tag_free ( struct mvs_info * mvi , u32 tag )
2009-05-09 01:44:01 +04:00
{
mvs_tag_clear ( mvi , tag ) ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
void mvs_tag_set ( struct mvs_info * mvi , unsigned int tag )
2009-05-09 01:44:01 +04:00
{
[SCSI] mvsas: Remove unused macros, variables and functions
Remove unused macros: VSR_PHY_VS0, VSR_PHY_VS1, MVS_SLOTS,
MVS_CAN_QUEUE, MVS_MSI, SG_MX, _MV_DUMP, MV_DISABLE_NCQ
Remove unused variables for mvs_info: irq, exp_req, cmd_size
Remove unused functions: mvs_get_sas_addr, mvs_hexdump,
mvs_hba_sb_dump, mvs_hab_memory_dump, mvs_hba_cq_dump
Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2011-05-24 18:35:09 +04:00
void * bitmap = mvi - > tags ;
2009-05-09 01:44:01 +04:00
set_bit ( tag , bitmap ) ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
inline int mvs_tag_alloc ( struct mvs_info * mvi , u32 * tag_out )
2009-05-09 01:44:01 +04:00
{
unsigned int index , tag ;
[SCSI] mvsas: Remove unused macros, variables and functions
Remove unused macros: VSR_PHY_VS0, VSR_PHY_VS1, MVS_SLOTS,
MVS_CAN_QUEUE, MVS_MSI, SG_MX, _MV_DUMP, MV_DISABLE_NCQ
Remove unused variables for mvs_info: irq, exp_req, cmd_size
Remove unused functions: mvs_get_sas_addr, mvs_hexdump,
mvs_hba_sb_dump, mvs_hab_memory_dump, mvs_hba_cq_dump
Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2011-05-24 18:35:09 +04:00
void * bitmap = mvi - > tags ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
index = find_first_zero_bit ( bitmap , mvi - > tags_num ) ;
2009-05-09 01:44:01 +04:00
tag = index ;
2009-05-09 01:46:40 +04:00
if ( tag > = mvi - > tags_num )
2009-05-09 01:44:01 +04:00
return - SAS_QUEUE_FULL ;
mvs_tag_set ( mvi , tag ) ;
* tag_out = tag ;
return 0 ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
void mvs_tag_init ( struct mvs_info * mvi )
{
int i ;
2009-05-09 01:46:40 +04:00
for ( i = 0 ; i < mvi - > tags_num ; + + i )
2009-05-09 01:44:01 +04:00
mvs_tag_clear ( mvi , i ) ;
}
2007-10-26 04:58:22 +04:00
2016-09-25 08:48:50 +03:00
static struct mvs_info * mvs_find_dev_mvi ( struct domain_device * dev )
2009-05-09 01:46:40 +04:00
{
unsigned long i = 0 , j = 0 , hi = 0 ;
struct sas_ha_struct * sha = dev - > port - > ha ;
struct mvs_info * mvi = NULL ;
struct asd_sas_phy * phy ;
while ( sha - > sas_port [ i ] ) {
if ( sha - > sas_port [ i ] = = dev - > port ) {
phy = container_of ( sha - > sas_port [ i ] - > phy_list . next ,
struct asd_sas_phy , port_phy_el ) ;
j = 0 ;
while ( sha - > sas_phy [ j ] ) {
if ( sha - > sas_phy [ j ] = = phy )
break ;
j + + ;
}
break ;
}
i + + ;
}
hi = j / ( ( struct mvs_prv_info * ) sha - > lldd_ha ) - > n_phy ;
mvi = ( ( struct mvs_prv_info * ) sha - > lldd_ha ) - > mvi [ hi ] ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
return mvi ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
}
2008-02-23 16:15:27 +03:00
2016-09-25 08:48:50 +03:00
static int mvs_find_dev_phyno ( struct domain_device * dev , int * phyno )
2009-05-09 01:46:40 +04:00
{
unsigned long i = 0 , j = 0 , n = 0 , num = 0 ;
2009-05-11 18:19:25 +04:00
struct mvs_device * mvi_dev = ( struct mvs_device * ) dev - > lldd_dev ;
struct mvs_info * mvi = mvi_dev - > mvi_info ;
2009-05-09 01:46:40 +04:00
struct sas_ha_struct * sha = dev - > port - > ha ;
while ( sha - > sas_port [ i ] ) {
if ( sha - > sas_port [ i ] = = dev - > port ) {
struct asd_sas_phy * phy ;
list_for_each_entry ( phy ,
& sha - > sas_port [ i ] - > phy_list , port_phy_el ) {
j = 0 ;
while ( sha - > sas_phy [ j ] ) {
if ( sha - > sas_phy [ j ] = = phy )
break ;
j + + ;
}
phyno [ n ] = ( j > = mvi - > chip - > n_phy ) ?
( j - mvi - > chip - > n_phy ) : j ;
num + + ;
n + + ;
2009-05-09 01:44:01 +04:00
}
break ;
}
2009-05-09 01:46:40 +04:00
i + + ;
}
return num ;
}
2011-05-24 18:26:50 +04:00
struct mvs_device * mvs_find_dev_by_reg_set ( struct mvs_info * mvi ,
u8 reg_set )
{
u32 dev_no ;
for ( dev_no = 0 ; dev_no < MVS_MAX_DEVICES ; dev_no + + ) {
if ( mvi - > devices [ dev_no ] . taskfileset = = MVS_ID_NOT_MAPPED )
continue ;
if ( mvi - > devices [ dev_no ] . taskfileset = = reg_set )
return & mvi - > devices [ dev_no ] ;
}
return NULL ;
}
2009-05-09 01:46:40 +04:00
static inline void mvs_free_reg_set ( struct mvs_info * mvi ,
struct mvs_device * dev )
{
if ( ! dev ) {
mv_printk ( " device has been free. \n " ) ;
return ;
}
if ( dev - > taskfileset = = MVS_ID_NOT_MAPPED )
return ;
MVS_CHIP_DISP - > free_reg_set ( mvi , & dev - > taskfileset ) ;
}
static inline u8 mvs_assign_reg_set ( struct mvs_info * mvi ,
struct mvs_device * dev )
{
if ( dev - > taskfileset ! = MVS_ID_NOT_MAPPED )
return 0 ;
return MVS_CHIP_DISP - > assign_reg_set ( mvi , & dev - > taskfileset ) ;
}
void mvs_phys_reset ( struct mvs_info * mvi , u32 phy_mask , int hard )
{
u32 no ;
for_each_phy ( phy_mask , phy_mask , no ) {
if ( ! ( phy_mask & 1 ) )
continue ;
MVS_CHIP_DISP - > phy_reset ( mvi , no , hard ) ;
}
}
int mvs_phy_control ( struct asd_sas_phy * sas_phy , enum phy_func func ,
void * funcdata )
{
int rc = 0 , phy_id = sas_phy - > id ;
u32 tmp , i = 0 , hi ;
struct sas_ha_struct * sha = sas_phy - > ha ;
struct mvs_info * mvi = NULL ;
while ( sha - > sas_phy [ i ] ) {
if ( sha - > sas_phy [ i ] = = sas_phy )
break ;
i + + ;
}
hi = i / ( ( struct mvs_prv_info * ) sha - > lldd_ha ) - > n_phy ;
mvi = ( ( struct mvs_prv_info * ) sha - > lldd_ha ) - > mvi [ hi ] ;
switch ( func ) {
case PHY_FUNC_SET_LINK_RATE :
MVS_CHIP_DISP - > phy_set_link_rate ( mvi , phy_id , funcdata ) ;
break ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:44:01 +04:00
case PHY_FUNC_HARD_RESET :
2009-05-09 01:46:40 +04:00
tmp = MVS_CHIP_DISP - > read_phy_ctl ( mvi , phy_id ) ;
2009-05-09 01:44:01 +04:00
if ( tmp & PHY_RST_HARD )
break ;
2011-05-24 18:36:02 +04:00
MVS_CHIP_DISP - > phy_reset ( mvi , phy_id , MVS_HARD_RESET ) ;
2009-05-09 01:44:01 +04:00
break ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
case PHY_FUNC_LINK_RESET :
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > phy_enable ( mvi , phy_id ) ;
2011-05-24 18:36:02 +04:00
MVS_CHIP_DISP - > phy_reset ( mvi , phy_id , MVS_SOFT_RESET ) ;
2009-05-09 01:44:01 +04:00
break ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
case PHY_FUNC_DISABLE :
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > phy_disable ( mvi , phy_id ) ;
break ;
2009-05-09 01:44:01 +04:00
case PHY_FUNC_RELEASE_SPINUP_HOLD :
default :
2011-09-29 05:48:02 +04:00
rc = - ENOSYS ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
msleep ( 200 ) ;
2007-10-26 04:58:22 +04:00
return rc ;
}
2012-12-22 01:08:55 +04:00
void mvs_set_sas_addr ( struct mvs_info * mvi , int port_id , u32 off_lo ,
u32 off_hi , u64 sas_addr )
2009-05-09 01:46:40 +04:00
{
u32 lo = ( u32 ) sas_addr ;
u32 hi = ( u32 ) ( sas_addr > > 32 ) ;
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , port_id , off_lo ) ;
MVS_CHIP_DISP - > write_port_cfg_data ( mvi , port_id , lo ) ;
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , port_id , off_hi ) ;
MVS_CHIP_DISP - > write_port_cfg_data ( mvi , port_id , hi ) ;
}
2009-05-09 01:44:01 +04:00
static void mvs_bytes_dmaed ( struct mvs_info * mvi , int i )
2008-03-27 09:53:47 +03:00
{
2009-05-09 01:44:01 +04:00
struct mvs_phy * phy = & mvi - > phy [ i ] ;
2009-05-09 01:46:40 +04:00
struct asd_sas_phy * sas_phy = & phy - > sas_phy ;
struct sas_ha_struct * sas_ha ;
2009-05-09 01:44:01 +04:00
if ( ! phy - > phy_attached )
return ;
2009-05-09 01:46:40 +04:00
if ( ! ( phy - > att_dev_info & PORT_DEV_TRGT_MASK )
& & phy - > phy_type & PORT_TYPE_SAS ) {
return ;
}
sas_ha = mvi - > sas ;
sas_ha - > notify_phy_event ( sas_phy , PHYE_OOB_DONE ) ;
2009-05-09 01:44:01 +04:00
if ( sas_phy - > phy ) {
struct sas_phy * sphy = sas_phy - > phy ;
sphy - > negotiated_linkrate = sas_phy - > linkrate ;
sphy - > minimum_linkrate = phy - > minimum_linkrate ;
sphy - > minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS ;
sphy - > maximum_linkrate = phy - > maximum_linkrate ;
2009-05-09 01:46:40 +04:00
sphy - > maximum_linkrate_hw = MVS_CHIP_DISP - > phy_max_link_rate ( ) ;
2008-03-27 09:53:47 +03:00
}
2009-05-09 01:44:01 +04:00
if ( phy - > phy_type & PORT_TYPE_SAS ) {
struct sas_identify_frame * id ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
id = ( struct sas_identify_frame * ) phy - > frame_rcvd ;
id - > dev_type = phy - > identify . device_type ;
id - > initiator_bits = SAS_PROTOCOL_ALL ;
id - > target_bits = phy - > identify . target_port_protocols ;
2011-09-29 11:33:49 +04:00
/* direct attached SAS device */
if ( phy - > att_dev_info & PORT_SSP_TRGT_MASK ) {
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , i , PHYR_PHY_STAT ) ;
MVS_CHIP_DISP - > write_port_cfg_data ( mvi , i , 0x00 ) ;
}
2009-05-09 01:44:01 +04:00
} else if ( phy - > phy_type & PORT_TYPE_SATA ) {
2009-05-09 01:46:40 +04:00
/*Nothing*/
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
mv_dprintk ( " phy %d byte dmaded. \n " , i + mvi - > id * mvi - > chip - > n_phy ) ;
sas_phy - > frame_rcvd_size = phy - > frame_rcvd_size ;
mvi - > sas - > notify_port_event ( sas_phy ,
2009-05-09 01:44:01 +04:00
PORTE_BYTES_DMAED ) ;
2008-03-27 09:53:47 +03:00
}
2009-05-09 01:44:01 +04:00
void mvs_scan_start ( struct Scsi_Host * shost )
2007-10-26 04:58:22 +04:00
{
2009-05-09 01:46:40 +04:00
int i , j ;
unsigned short core_nr ;
struct mvs_info * mvi ;
struct sas_ha_struct * sha = SHOST_TO_SAS_HA ( shost ) ;
2011-05-24 18:37:25 +04:00
struct mvs_prv_info * mvs_prv = sha - > lldd_ha ;
2009-05-09 01:46:40 +04:00
core_nr = ( ( struct mvs_prv_info * ) sha - > lldd_ha ) - > n_host ;
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
for ( j = 0 ; j < core_nr ; j + + ) {
mvi = ( ( struct mvs_prv_info * ) sha - > lldd_ha ) - > mvi [ j ] ;
for ( i = 0 ; i < mvi - > chip - > n_phy ; + + i )
mvs_bytes_dmaed ( mvi , i ) ;
2009-05-09 01:44:01 +04:00
}
2011-05-24 18:37:25 +04:00
mvs_prv - > scan_finished = 1 ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:44:01 +04:00
int mvs_scan_finished ( struct Scsi_Host * shost , unsigned long time )
2007-10-26 04:58:22 +04:00
{
2011-05-24 18:37:25 +04:00
struct sas_ha_struct * sha = SHOST_TO_SAS_HA ( shost ) ;
struct mvs_prv_info * mvs_prv = sha - > lldd_ha ;
if ( mvs_prv - > scan_finished = = 0 )
2009-05-09 01:44:01 +04:00
return 0 ;
2011-05-24 18:37:25 +04:00
2011-12-20 04:42:34 +04:00
sas_drain_work ( sha ) ;
2009-05-09 01:44:01 +04:00
return 1 ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:44:01 +04:00
static int mvs_task_prep_smp ( struct mvs_info * mvi ,
struct mvs_task_exec_info * tei )
2007-10-26 04:58:22 +04:00
{
2009-05-09 01:44:01 +04:00
int elem , rc , i ;
2013-01-29 20:25:53 +04:00
struct sas_ha_struct * sha = mvi - > sas ;
2009-05-09 01:44:01 +04:00
struct sas_task * task = tei - > task ;
struct mvs_cmd_hdr * hdr = tei - > hdr ;
2009-05-09 01:46:40 +04:00
struct domain_device * dev = task - > dev ;
struct asd_sas_port * sas_port = dev - > port ;
2013-01-29 20:25:53 +04:00
struct sas_phy * sphy = dev - > phy ;
struct asd_sas_phy * sas_phy = sha - > sas_phy [ sphy - > number ] ;
2009-05-09 01:44:01 +04:00
struct scatterlist * sg_req , * sg_resp ;
u32 req_len , resp_len , tag = tei - > tag ;
void * buf_tmp ;
u8 * buf_oaf ;
dma_addr_t buf_tmp_dma ;
2009-05-09 01:46:40 +04:00
void * buf_prd ;
2009-05-09 01:44:01 +04:00
struct mvs_slot_info * slot = & mvi - > slot_info [ tag ] ;
u32 flags = ( tei - > n_elem < < MCH_PRD_LEN_SHIFT ) ;
[SCSI] mvsas: Remove unused macros, variables and functions
Remove unused macros: VSR_PHY_VS0, VSR_PHY_VS1, MVS_SLOTS,
MVS_CAN_QUEUE, MVS_MSI, SG_MX, _MV_DUMP, MV_DISABLE_NCQ
Remove unused variables for mvs_info: irq, exp_req, cmd_size
Remove unused functions: mvs_get_sas_addr, mvs_hexdump,
mvs_hba_sb_dump, mvs_hab_memory_dump, mvs_hba_cq_dump
Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2011-05-24 18:35:09 +04:00
2009-05-09 01:44:01 +04:00
/*
* DMA - map SMP request , response buffers
*/
sg_req = & task - > smp_task . smp_req ;
2009-05-09 01:46:40 +04:00
elem = dma_map_sg ( mvi - > dev , sg_req , 1 , PCI_DMA_TODEVICE ) ;
2009-05-09 01:44:01 +04:00
if ( ! elem )
return - ENOMEM ;
req_len = sg_dma_len ( sg_req ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
sg_resp = & task - > smp_task . smp_resp ;
2009-05-09 01:46:40 +04:00
elem = dma_map_sg ( mvi - > dev , sg_resp , 1 , PCI_DMA_FROMDEVICE ) ;
2009-05-09 01:44:01 +04:00
if ( ! elem ) {
rc = - ENOMEM ;
goto err_out ;
}
2009-05-09 01:46:40 +04:00
resp_len = SB_RFB_MAX ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
/* must be in dwords */
if ( ( req_len & 0x3 ) | | ( resp_len & 0x3 ) ) {
rc = - EINVAL ;
goto err_out_2 ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:44:01 +04:00
/*
* arrange MVS_SLOT_BUF_SZ - sized DMA buffer according to our needs
*/
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */
2009-05-09 01:44:01 +04:00
buf_tmp = slot - > buf ;
buf_tmp_dma = slot - > buf_dma ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
hdr - > cmd_tbl = cpu_to_le64 ( sg_dma_address ( sg_req ) ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
buf_oaf = buf_tmp ;
hdr - > open_frame = cpu_to_le64 ( buf_tmp_dma ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
buf_tmp + = MVS_OAF_SZ ;
buf_tmp_dma + = MVS_OAF_SZ ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
/* region 3: PRD table *********************************** */
2009-05-09 01:44:01 +04:00
buf_prd = buf_tmp ;
if ( tei - > n_elem )
hdr - > prd_tbl = cpu_to_le64 ( buf_tmp_dma ) ;
else
hdr - > prd_tbl = 0 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
i = MVS_CHIP_DISP - > prd_size ( ) * tei - > n_elem ;
2009-05-09 01:44:01 +04:00
buf_tmp + = i ;
buf_tmp_dma + = i ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
slot - > response = buf_tmp ;
hdr - > status_buf = cpu_to_le64 ( buf_tmp_dma ) ;
2009-05-09 01:46:40 +04:00
if ( mvi - > flags & MVF_FLAG_SOC )
hdr - > reserved [ 0 ] = 0 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
/*
* Fill in TX ring and command slot header
*/
slot - > tx = mvi - > tx_prod ;
mvi - > tx [ mvi - > tx_prod ] = cpu_to_le32 ( ( TXQ_CMD_SMP < < TXQ_CMD_SHIFT ) |
TXQ_MODE_I | tag |
2013-01-29 20:25:53 +04:00
( MVS_PHY_ID < < TXQ_PHY_SHIFT ) ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
hdr - > flags | = flags ;
hdr - > lens = cpu_to_le32 ( ( ( resp_len / 4 ) < < 16 ) | ( ( req_len - 4 ) / 4 ) ) ;
hdr - > tags = cpu_to_le32 ( tag ) ;
hdr - > data_len = 0 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
/* generate open address frame hdr (first 12 bytes) */
2009-05-09 01:46:40 +04:00
/* initiator, SMP, ftype 1h */
buf_oaf [ 0 ] = ( 1 < < 7 ) | ( PROTOCOL_SMP < < 4 ) | 0x01 ;
2011-09-29 11:32:37 +04:00
buf_oaf [ 1 ] = min ( sas_port - > linkrate , dev - > linkrate ) & 0xf ;
2009-05-09 01:44:01 +04:00
* ( u16 * ) ( buf_oaf + 2 ) = 0xFFFF ; /* SAS SPEC */
2009-05-09 01:46:40 +04:00
memcpy ( buf_oaf + 4 , dev - > sas_addr , SAS_ADDR_SIZE ) ;
2009-05-09 01:44:01 +04:00
/* fill in PRD (scatter/gather) table, if any */
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > make_prd ( task - > scatter , tei - > n_elem , buf_prd ) ;
2007-10-26 04:58:22 +04:00
return 0 ;
2009-05-09 01:44:01 +04:00
err_out_2 :
2009-05-09 01:46:40 +04:00
dma_unmap_sg ( mvi - > dev , & tei - > task - > smp_task . smp_resp , 1 ,
2009-05-09 01:44:01 +04:00
PCI_DMA_FROMDEVICE ) ;
2007-10-26 04:58:22 +04:00
err_out :
2009-05-09 01:46:40 +04:00
dma_unmap_sg ( mvi - > dev , & tei - > task - > smp_task . smp_req , 1 ,
2009-05-09 01:44:01 +04:00
PCI_DMA_TODEVICE ) ;
2008-02-23 16:15:27 +03:00
return rc ;
}
2009-05-09 01:44:01 +04:00
static u32 mvs_get_ncq_tag ( struct sas_task * task , u32 * tag )
2008-02-23 16:15:27 +03:00
{
2009-05-09 01:44:01 +04:00
struct ata_queued_cmd * qc = task - > uldd_task ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:44:01 +04:00
if ( qc ) {
if ( qc - > tf . command = = ATA_CMD_FPDMA_WRITE | |
2016-04-25 13:45:44 +03:00
qc - > tf . command = = ATA_CMD_FPDMA_READ | |
qc - > tf . command = = ATA_CMD_FPDMA_RECV | |
2016-04-25 13:45:45 +03:00
qc - > tf . command = = ATA_CMD_FPDMA_SEND | |
qc - > tf . command = = ATA_CMD_NCQ_NON_DATA ) {
2009-05-09 01:44:01 +04:00
* tag = qc - > tag ;
return 1 ;
}
2008-02-23 16:15:27 +03:00
}
2009-05-09 01:44:01 +04:00
return 0 ;
2008-02-23 16:15:27 +03:00
}
2009-05-09 01:44:01 +04:00
static int mvs_task_prep_ata ( struct mvs_info * mvi ,
struct mvs_task_exec_info * tei )
2007-10-26 04:58:22 +04:00
{
struct sas_task * task = tei - > task ;
struct domain_device * dev = task - > dev ;
2009-05-15 04:41:21 +04:00
struct mvs_device * mvi_dev = dev - > lldd_dev ;
2007-10-26 04:58:22 +04:00
struct mvs_cmd_hdr * hdr = tei - > hdr ;
struct asd_sas_port * sas_port = dev - > port ;
2008-02-23 16:15:27 +03:00
struct mvs_slot_info * slot ;
2009-05-09 01:46:40 +04:00
void * buf_prd ;
u32 tag = tei - > tag , hdr_tag ;
u32 flags , del_q ;
2007-10-26 04:58:22 +04:00
void * buf_tmp ;
u8 * buf_cmd , * buf_oaf ;
dma_addr_t buf_tmp_dma ;
2008-02-23 16:15:27 +03:00
u32 i , req_len , resp_len ;
const u32 max_resp_len = SB_RFB_MAX ;
2009-05-09 01:46:40 +04:00
if ( mvs_assign_reg_set ( mvi , mvi_dev ) = = MVS_ID_NOT_MAPPED ) {
mv_dprintk ( " Have not enough regiset for dev %d. \n " ,
mvi_dev - > device_id ) ;
2008-02-23 16:15:27 +03:00
return - EBUSY ;
2009-05-09 01:46:40 +04:00
}
2008-02-23 16:15:27 +03:00
slot = & mvi - > slot_info [ tag ] ;
slot - > tx = mvi - > tx_prod ;
2009-05-09 01:46:40 +04:00
del_q = TXQ_MODE_I | tag |
( TXQ_CMD_STP < < TXQ_CMD_SHIFT ) |
2015-04-16 08:16:01 +03:00
( ( sas_port - > phy_mask & TXQ_PHY_MASK ) < < TXQ_PHY_SHIFT ) |
2009-05-09 01:46:40 +04:00
( mvi_dev - > taskfileset < < TXQ_SRS_SHIFT ) ;
mvi - > tx [ mvi - > tx_prod ] = cpu_to_le32 ( del_q ) ;
if ( task - > data_dir = = DMA_FROM_DEVICE )
flags = ( MVS_CHIP_DISP - > prd_count ( ) < < MCH_PRD_LEN_SHIFT ) ;
else
flags = ( tei - > n_elem < < MCH_PRD_LEN_SHIFT ) ;
2011-05-24 18:33:11 +04:00
2007-10-26 04:58:22 +04:00
if ( task - > ata_task . use_ncq )
flags | = MCH_FPDMA ;
2014-11-05 15:08:20 +03:00
if ( dev - > sata_dev . class = = ATA_DEV_ATAPI ) {
2008-02-23 16:15:27 +03:00
if ( task - > ata_task . fis . command ! = ATA_CMD_ID_ATAPI )
flags | = MCH_ATAPI ;
}
2007-10-26 04:58:22 +04:00
hdr - > flags = cpu_to_le32 ( flags ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
if ( task - > ata_task . use_ncq & & mvs_get_ncq_tag ( task , & hdr_tag ) )
task - > ata_task . fis . sector_count | = ( u8 ) ( hdr_tag < < 3 ) ;
2008-03-27 09:54:50 +03:00
else
2009-05-09 01:46:40 +04:00
hdr_tag = tag ;
hdr - > tags = cpu_to_le32 ( hdr_tag ) ;
2007-10-26 04:58:22 +04:00
hdr - > data_len = cpu_to_le32 ( task - > total_xfer_len ) ;
/*
* arrange MVS_SLOT_BUF_SZ - sized DMA buffer according to our needs
*/
2008-02-23 16:15:27 +03:00
/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
buf_cmd = buf_tmp = slot - > buf ;
2007-10-26 04:58:22 +04:00
buf_tmp_dma = slot - > buf_dma ;
hdr - > cmd_tbl = cpu_to_le64 ( buf_tmp_dma ) ;
buf_tmp + = MVS_ATA_CMD_SZ ;
buf_tmp_dma + = MVS_ATA_CMD_SZ ;
2008-02-23 16:15:27 +03:00
/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
2007-10-26 04:58:22 +04:00
/* used for STP. unused for SATA? */
buf_oaf = buf_tmp ;
hdr - > open_frame = cpu_to_le64 ( buf_tmp_dma ) ;
buf_tmp + = MVS_OAF_SZ ;
buf_tmp_dma + = MVS_OAF_SZ ;
2008-02-23 16:15:27 +03:00
/* region 3: PRD table ********************************************* */
2007-10-26 04:58:22 +04:00
buf_prd = buf_tmp ;
2009-05-09 01:46:40 +04:00
2008-02-23 16:15:27 +03:00
if ( tei - > n_elem )
hdr - > prd_tbl = cpu_to_le64 ( buf_tmp_dma ) ;
else
hdr - > prd_tbl = 0 ;
2009-05-09 01:46:40 +04:00
i = MVS_CHIP_DISP - > prd_size ( ) * MVS_CHIP_DISP - > prd_count ( ) ;
2007-10-26 04:58:22 +04:00
buf_tmp + = i ;
buf_tmp_dma + = i ;
2008-02-23 16:15:27 +03:00
/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
2007-10-26 04:58:22 +04:00
slot - > response = buf_tmp ;
hdr - > status_buf = cpu_to_le64 ( buf_tmp_dma ) ;
2009-05-09 01:46:40 +04:00
if ( mvi - > flags & MVF_FLAG_SOC )
hdr - > reserved [ 0 ] = 0 ;
2007-10-26 04:58:22 +04:00
2008-02-23 16:15:27 +03:00
req_len = sizeof ( struct host_to_dev_fis ) ;
2007-10-26 04:58:22 +04:00
resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
2008-02-23 16:15:27 +03:00
sizeof ( struct mvs_err_info ) - i ;
2007-10-26 04:58:22 +04:00
/* request, response lengths */
2008-02-23 16:15:27 +03:00
resp_len = min ( resp_len , max_resp_len ) ;
2007-10-26 04:58:22 +04:00
hdr - > lens = cpu_to_le32 ( ( ( resp_len / 4 ) < < 16 ) | ( req_len / 4 ) ) ;
2009-05-09 01:46:40 +04:00
if ( likely ( ! task - > ata_task . device_control_reg_update ) )
task - > ata_task . fis . flags | = 0x80 ; /* C=1: update ATA cmd reg */
2007-10-26 04:58:22 +04:00
/* fill in command FIS and ATAPI CDB */
2008-02-23 16:15:27 +03:00
memcpy ( buf_cmd , & task - > ata_task . fis , sizeof ( struct host_to_dev_fis ) ) ;
2014-11-05 15:08:20 +03:00
if ( dev - > sata_dev . class = = ATA_DEV_ATAPI )
2008-02-23 16:15:27 +03:00
memcpy ( buf_cmd + STP_ATAPI_CMD ,
task - > ata_task . atapi_packet , 16 ) ;
/* generate open address frame hdr (first 12 bytes) */
2009-05-09 01:46:40 +04:00
/* initiator, STP, ftype 1h */
buf_oaf [ 0 ] = ( 1 < < 7 ) | ( PROTOCOL_STP < < 4 ) | 0x1 ;
2011-09-29 11:32:37 +04:00
buf_oaf [ 1 ] = min ( sas_port - > linkrate , dev - > linkrate ) & 0xf ;
2009-05-09 01:46:40 +04:00
* ( u16 * ) ( buf_oaf + 2 ) = cpu_to_be16 ( mvi_dev - > device_id + 1 ) ;
memcpy ( buf_oaf + 4 , dev - > sas_addr , SAS_ADDR_SIZE ) ;
2007-10-26 04:58:22 +04:00
/* fill in PRD (scatter/gather) table, if any */
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > make_prd ( task - > scatter , tei - > n_elem , buf_prd ) ;
2011-05-24 18:33:11 +04:00
2009-05-09 01:46:40 +04:00
if ( task - > data_dir = = DMA_FROM_DEVICE )
2011-05-24 18:33:11 +04:00
MVS_CHIP_DISP - > dma_fix ( mvi , sas_port - > phy_mask ,
2009-05-09 01:46:40 +04:00
TRASH_BUCKET_SIZE , tei - > n_elem , buf_prd ) ;
2011-05-24 18:33:11 +04:00
2007-10-26 04:58:22 +04:00
return 0 ;
}
static int mvs_task_prep_ssp ( struct mvs_info * mvi ,
2009-05-09 01:46:40 +04:00
struct mvs_task_exec_info * tei , int is_tmf ,
struct mvs_tmf_task * tmf )
2007-10-26 04:58:22 +04:00
{
struct sas_task * task = tei - > task ;
struct mvs_cmd_hdr * hdr = tei - > hdr ;
2008-02-23 16:15:27 +03:00
struct mvs_port * port = tei - > port ;
2009-05-09 01:46:40 +04:00
struct domain_device * dev = task - > dev ;
2009-05-15 04:41:21 +04:00
struct mvs_device * mvi_dev = dev - > lldd_dev ;
2009-05-09 01:46:40 +04:00
struct asd_sas_port * sas_port = dev - > port ;
2007-10-26 04:58:22 +04:00
struct mvs_slot_info * slot ;
2009-05-09 01:46:40 +04:00
void * buf_prd ;
2007-10-26 04:58:22 +04:00
struct ssp_frame_hdr * ssp_hdr ;
void * buf_tmp ;
u8 * buf_cmd , * buf_oaf , fburst = 0 ;
dma_addr_t buf_tmp_dma ;
u32 flags ;
2008-02-23 16:15:27 +03:00
u32 resp_len , req_len , i , tag = tei - > tag ;
const u32 max_resp_len = SB_RFB_MAX ;
2009-05-09 01:46:40 +04:00
u32 phy_mask ;
2007-10-26 04:58:22 +04:00
slot = & mvi - > slot_info [ tag ] ;
2009-05-09 01:46:40 +04:00
phy_mask = ( ( port - > wide_port_phymap ) ? port - > wide_port_phymap :
sas_port - > phy_mask ) & TXQ_PHY_MASK ;
2008-02-23 16:15:27 +03:00
slot - > tx = mvi - > tx_prod ;
mvi - > tx [ mvi - > tx_prod ] = cpu_to_le32 ( TXQ_MODE_I | tag |
( TXQ_CMD_SSP < < TXQ_CMD_SHIFT ) |
2008-03-27 09:54:50 +03:00
( phy_mask < < TXQ_PHY_SHIFT ) ) ;
2007-10-26 04:58:22 +04:00
flags = MCH_RETRY ;
if ( task - > ssp_task . enable_first_burst ) {
flags | = MCH_FBURST ;
fburst = ( 1 < < 7 ) ;
}
2009-05-11 16:01:55 +04:00
if ( is_tmf )
flags | = ( MCH_SSP_FR_TASK < < MCH_SSP_FR_TYPE_SHIFT ) ;
2011-05-24 18:37:25 +04:00
else
flags | = ( MCH_SSP_FR_CMD < < MCH_SSP_FR_TYPE_SHIFT ) ;
2009-05-11 16:01:55 +04:00
hdr - > flags = cpu_to_le32 ( flags | ( tei - > n_elem < < MCH_PRD_LEN_SHIFT ) ) ;
2007-10-26 04:58:22 +04:00
hdr - > tags = cpu_to_le32 ( tag ) ;
hdr - > data_len = cpu_to_le32 ( task - > total_xfer_len ) ;
/*
* arrange MVS_SLOT_BUF_SZ - sized DMA buffer according to our needs
*/
2008-02-23 16:15:27 +03:00
/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
buf_cmd = buf_tmp = slot - > buf ;
2007-10-26 04:58:22 +04:00
buf_tmp_dma = slot - > buf_dma ;
hdr - > cmd_tbl = cpu_to_le64 ( buf_tmp_dma ) ;
buf_tmp + = MVS_SSP_CMD_SZ ;
buf_tmp_dma + = MVS_SSP_CMD_SZ ;
2008-02-23 16:15:27 +03:00
/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
2007-10-26 04:58:22 +04:00
buf_oaf = buf_tmp ;
hdr - > open_frame = cpu_to_le64 ( buf_tmp_dma ) ;
buf_tmp + = MVS_OAF_SZ ;
buf_tmp_dma + = MVS_OAF_SZ ;
2008-02-23 16:15:27 +03:00
/* region 3: PRD table ********************************************* */
2007-10-26 04:58:22 +04:00
buf_prd = buf_tmp ;
2008-02-23 16:15:27 +03:00
if ( tei - > n_elem )
hdr - > prd_tbl = cpu_to_le64 ( buf_tmp_dma ) ;
else
hdr - > prd_tbl = 0 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
i = MVS_CHIP_DISP - > prd_size ( ) * tei - > n_elem ;
2007-10-26 04:58:22 +04:00
buf_tmp + = i ;
buf_tmp_dma + = i ;
2008-02-23 16:15:27 +03:00
/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
2007-10-26 04:58:22 +04:00
slot - > response = buf_tmp ;
hdr - > status_buf = cpu_to_le64 ( buf_tmp_dma ) ;
2009-05-09 01:46:40 +04:00
if ( mvi - > flags & MVF_FLAG_SOC )
hdr - > reserved [ 0 ] = 0 ;
2007-10-26 04:58:22 +04:00
resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
2008-02-23 16:15:27 +03:00
sizeof ( struct mvs_err_info ) - i ;
resp_len = min ( resp_len , max_resp_len ) ;
req_len = sizeof ( struct ssp_frame_hdr ) + 28 ;
2007-10-26 04:58:22 +04:00
/* request, response lengths */
hdr - > lens = cpu_to_le32 ( ( ( resp_len / 4 ) < < 16 ) | ( req_len / 4 ) ) ;
/* generate open address frame hdr (first 12 bytes) */
2009-05-09 01:46:40 +04:00
/* initiator, SSP, ftype 1h */
buf_oaf [ 0 ] = ( 1 < < 7 ) | ( PROTOCOL_SSP < < 4 ) | 0x1 ;
2011-09-29 11:32:37 +04:00
buf_oaf [ 1 ] = min ( sas_port - > linkrate , dev - > linkrate ) & 0xf ;
2009-05-09 01:46:40 +04:00
* ( u16 * ) ( buf_oaf + 2 ) = cpu_to_be16 ( mvi_dev - > device_id + 1 ) ;
memcpy ( buf_oaf + 4 , dev - > sas_addr , SAS_ADDR_SIZE ) ;
2007-10-26 04:58:22 +04:00
2008-02-23 16:15:27 +03:00
/* fill in SSP frame header (Command Table.SSP frame header) */
ssp_hdr = ( struct ssp_frame_hdr * ) buf_cmd ;
2009-05-09 01:46:40 +04:00
if ( is_tmf )
ssp_hdr - > frame_type = SSP_TASK ;
else
ssp_hdr - > frame_type = SSP_COMMAND ;
memcpy ( ssp_hdr - > hashed_dest_addr , dev - > hashed_sas_addr ,
2007-10-26 04:58:22 +04:00
HASHED_SAS_ADDR_SIZE ) ;
memcpy ( ssp_hdr - > hashed_src_addr ,
2009-05-09 01:46:40 +04:00
dev - > hashed_sas_addr , HASHED_SAS_ADDR_SIZE ) ;
2007-10-26 04:58:22 +04:00
ssp_hdr - > tag = cpu_to_be16 ( tag ) ;
2009-05-09 01:46:40 +04:00
/* fill in IU for TASK and Command Frame */
2007-10-26 04:58:22 +04:00
buf_cmd + = sizeof ( * ssp_hdr ) ;
memcpy ( buf_cmd , & task - > ssp_task . LUN , 8 ) ;
2009-05-09 01:46:40 +04:00
if ( ssp_hdr - > frame_type ! = SSP_TASK ) {
buf_cmd [ 9 ] = fburst | task - > ssp_task . task_attr |
( task - > ssp_task . task_prio < < 3 ) ;
2013-05-08 02:38:18 +04:00
memcpy ( buf_cmd + 12 , task - > ssp_task . cmd - > cmnd ,
task - > ssp_task . cmd - > cmd_len ) ;
2009-05-09 01:46:40 +04:00
} else {
buf_cmd [ 10 ] = tmf - > tmf ;
switch ( tmf - > tmf ) {
case TMF_ABORT_TASK :
case TMF_QUERY_TASK :
buf_cmd [ 12 ] =
( tmf - > tag_of_task_to_be_managed > > 8 ) & 0xff ;
buf_cmd [ 13 ] =
tmf - > tag_of_task_to_be_managed & 0xff ;
break ;
default :
break ;
}
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
/* fill in PRD (scatter/gather) table, if any */
MVS_CHIP_DISP - > make_prd ( task - > scatter , tei - > n_elem , buf_prd ) ;
2007-10-26 04:58:22 +04:00
return 0 ;
}
2013-05-08 01:44:06 +04:00
# define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == SAS_PHY_UNUSED)))
2011-04-26 17:36:51 +04:00
static int mvs_task_prep ( struct sas_task * task , struct mvs_info * mvi , int is_tmf ,
struct mvs_tmf_task * tmf , int * pass )
2007-10-26 04:58:22 +04:00
{
2008-02-23 16:15:27 +03:00
struct domain_device * dev = task - > dev ;
2011-04-26 17:36:51 +04:00
struct mvs_device * mvi_dev = dev - > lldd_dev ;
2007-10-26 04:58:22 +04:00
struct mvs_task_exec_info tei ;
2008-03-27 09:54:50 +03:00
struct mvs_slot_info * slot ;
2011-04-26 17:36:51 +04:00
u32 tag = 0xdeadbeef , n_elem = 0 ;
int rc = 0 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( ! dev - > port ) {
2011-04-26 17:36:51 +04:00
struct task_status_struct * tsm = & task - > task_status ;
2009-05-09 01:46:40 +04:00
tsm - > resp = SAS_TASK_UNDELIVERED ;
tsm - > stat = SAS_PHY_DOWN ;
2011-04-26 17:36:51 +04:00
/*
* libsas will use dev - > port , should
* not call task_done for sata
*/
2013-05-08 01:44:06 +04:00
if ( dev - > dev_type ! = SAS_SATA_DEV )
2011-04-26 17:36:51 +04:00
task - > task_done ( task ) ;
return rc ;
2009-05-09 01:46:40 +04:00
}
2011-04-26 17:36:51 +04:00
if ( DEV_IS_GONE ( mvi_dev ) ) {
if ( mvi_dev )
mv_dprintk ( " device %d not ready. \n " ,
mvi_dev - > device_id ) ;
else
mv_dprintk ( " device %016llx not ready. \n " ,
SAS_ADDR ( dev - > sas_addr ) ) ;
2009-05-09 01:46:40 +04:00
2015-11-30 17:32:17 +03:00
rc = SAS_PHY_DOWN ;
return rc ;
2011-04-26 17:36:51 +04:00
}
tei . port = dev - > port - > lldd_port ;
if ( tei . port & & ! tei . port - > port_attached & & ! tmf ) {
if ( sas_protocol_ata ( task - > task_proto ) ) {
struct task_status_struct * ts = & task - > task_status ;
mv_dprintk ( " SATA/STP port %d does not attach "
" device. \n " , dev - > port - > id ) ;
ts - > resp = SAS_TASK_COMPLETE ;
ts - > stat = SAS_PHY_DOWN ;
2009-05-09 01:46:40 +04:00
2011-04-26 17:36:51 +04:00
task - > task_done ( task ) ;
2009-05-09 01:44:01 +04:00
} else {
2011-04-26 17:36:51 +04:00
struct task_status_struct * ts = & task - > task_status ;
mv_dprintk ( " SAS port %d does not attach "
" device. \n " , dev - > port - > id ) ;
ts - > resp = SAS_TASK_UNDELIVERED ;
ts - > stat = SAS_PHY_DOWN ;
task - > task_done ( task ) ;
2009-05-09 01:44:01 +04:00
}
2011-04-26 17:36:51 +04:00
return rc ;
}
2009-05-09 01:44:01 +04:00
2011-04-26 17:36:51 +04:00
if ( ! sas_protocol_ata ( task - > task_proto ) ) {
if ( task - > num_scatter ) {
n_elem = dma_map_sg ( mvi - > dev ,
task - > scatter ,
task - > num_scatter ,
task - > data_dir ) ;
if ( ! n_elem ) {
rc = - ENOMEM ;
goto prep_out ;
}
}
} else {
n_elem = task - > num_scatter ;
}
2009-05-09 01:46:40 +04:00
2011-04-26 17:36:51 +04:00
rc = mvs_tag_alloc ( mvi , & tag ) ;
if ( rc )
goto err_out ;
2009-05-09 01:46:40 +04:00
2011-04-26 17:36:51 +04:00
slot = & mvi - > slot_info [ tag ] ;
2009-05-09 01:46:40 +04:00
2011-04-26 17:36:51 +04:00
task - > lldd_task = NULL ;
slot - > n_elem = n_elem ;
slot - > slot_tag = tag ;
2017-07-06 11:13:08 +03:00
slot - > buf = dma_pool_alloc ( mvi - > dma_pool , GFP_ATOMIC , & slot - > buf_dma ) ;
2016-10-31 18:04:10 +03:00
if ( ! slot - > buf ) {
rc = - ENOMEM ;
2011-04-26 17:36:51 +04:00
goto err_out_tag ;
2016-10-31 18:04:10 +03:00
}
2011-04-26 17:36:51 +04:00
memset ( slot - > buf , 0 , MVS_SLOT_BUF_SZ ) ;
tei . task = task ;
tei . hdr = & mvi - > slot [ tag ] ;
tei . tag = tag ;
tei . n_elem = n_elem ;
switch ( task - > task_proto ) {
case SAS_PROTOCOL_SMP :
rc = mvs_task_prep_smp ( mvi , & tei ) ;
break ;
case SAS_PROTOCOL_SSP :
rc = mvs_task_prep_ssp ( mvi , & tei , is_tmf , tmf ) ;
break ;
case SAS_PROTOCOL_SATA :
case SAS_PROTOCOL_STP :
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP :
rc = mvs_task_prep_ata ( mvi , & tei ) ;
break ;
default :
dev_printk ( KERN_ERR , mvi - > dev ,
" unknown sas_task proto: 0x%x \n " ,
task - > task_proto ) ;
rc = - EINVAL ;
break ;
}
2009-05-09 01:44:01 +04:00
2011-04-26 17:36:51 +04:00
if ( rc ) {
mv_dprintk ( " rc is %x \n " , rc ) ;
goto err_out_slot_buf ;
}
slot - > task = task ;
slot - > port = tei . port ;
task - > lldd_task = slot ;
list_add_tail ( & slot - > entry , & tei . port - > list ) ;
spin_lock ( & task - > task_state_lock ) ;
task - > task_state_flags | = SAS_TASK_AT_INITIATOR ;
spin_unlock ( & task - > task_state_lock ) ;
mvi_dev - > running_req + + ;
+ + ( * pass ) ;
mvi - > tx_prod = ( mvi - > tx_prod + 1 ) & ( MVS_CHIP_SLOT_SZ - 1 ) ;
2010-02-15 09:00:00 +03:00
2011-04-26 17:36:51 +04:00
return rc ;
2009-05-09 01:44:01 +04:00
2011-04-26 17:36:51 +04:00
err_out_slot_buf :
2017-07-06 11:13:08 +03:00
dma_pool_free ( mvi - > dma_pool , slot - > buf , slot - > buf_dma ) ;
2009-05-09 01:44:01 +04:00
err_out_tag :
mvs_tag_free ( mvi , tag ) ;
err_out :
2009-05-09 01:46:40 +04:00
2011-04-26 17:36:51 +04:00
dev_printk ( KERN_ERR , mvi - > dev , " mvsas prep failed[%d]! \n " , rc ) ;
if ( ! sas_protocol_ata ( task - > task_proto ) )
2009-05-09 01:44:01 +04:00
if ( n_elem )
2011-04-26 17:36:51 +04:00
dma_unmap_sg ( mvi - > dev , task - > scatter , n_elem ,
task - > data_dir ) ;
prep_out :
return rc ;
}
2014-11-05 12:36:28 +03:00
static int mvs_task_exec ( struct sas_task * task , gfp_t gfp_flags ,
2011-04-26 17:36:51 +04:00
struct completion * completion , int is_tmf ,
struct mvs_tmf_task * tmf )
{
struct mvs_info * mvi = NULL ;
u32 rc = 0 ;
u32 pass = 0 ;
unsigned long flags = 0 ;
mvi = ( ( struct mvs_device * ) task - > dev - > lldd_dev ) - > mvi_info ;
spin_lock_irqsave ( & mvi - > lock , flags ) ;
rc = mvs_task_prep ( task , mvi , is_tmf , tmf , & pass ) ;
if ( rc )
dev_printk ( KERN_ERR , mvi - > dev , " mvsas exec failed[%d]! \n " , rc ) ;
if ( likely ( pass ) )
MVS_CHIP_DISP - > start_delivery ( mvi , ( mvi - > tx_prod - 1 ) &
( MVS_CHIP_SLOT_SZ - 1 ) ) ;
2009-05-11 16:05:26 +04:00
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
2011-04-26 17:36:51 +04:00
return rc ;
}
2014-11-05 12:36:28 +03:00
int mvs_queue_command ( struct sas_task * task , gfp_t gfp_flags )
2009-05-09 01:46:40 +04:00
{
2014-11-05 12:36:28 +03:00
return mvs_task_exec ( task , gfp_flags , NULL , 0 , NULL ) ;
2009-05-09 01:46:40 +04:00
}
2009-05-09 01:44:01 +04:00
static void mvs_slot_free ( struct mvs_info * mvi , u32 rx_desc )
{
u32 slot_idx = rx_desc & RXQ_SLOT_MASK ;
mvs_tag_clear ( mvi , slot_idx ) ;
}
static void mvs_slot_task_free ( struct mvs_info * mvi , struct sas_task * task ,
struct mvs_slot_info * slot , u32 slot_idx )
{
2015-08-21 07:29:22 +03:00
if ( ! slot )
return ;
2009-05-09 01:46:40 +04:00
if ( ! slot - > task )
return ;
2009-05-09 01:44:01 +04:00
if ( ! sas_protocol_ata ( task - > task_proto ) )
if ( slot - > n_elem )
2009-05-09 01:46:40 +04:00
dma_unmap_sg ( mvi - > dev , task - > scatter ,
2009-05-09 01:44:01 +04:00
slot - > n_elem , task - > data_dir ) ;
switch ( task - > task_proto ) {
case SAS_PROTOCOL_SMP :
2009-05-09 01:46:40 +04:00
dma_unmap_sg ( mvi - > dev , & task - > smp_task . smp_resp , 1 ,
2009-05-09 01:44:01 +04:00
PCI_DMA_FROMDEVICE ) ;
2009-05-09 01:46:40 +04:00
dma_unmap_sg ( mvi - > dev , & task - > smp_task . smp_req , 1 ,
2009-05-09 01:44:01 +04:00
PCI_DMA_TODEVICE ) ;
break ;
case SAS_PROTOCOL_SATA :
case SAS_PROTOCOL_STP :
case SAS_PROTOCOL_SSP :
default :
/* do nothing */
break ;
}
2011-04-26 17:36:51 +04:00
if ( slot - > buf ) {
2017-07-06 11:13:08 +03:00
dma_pool_free ( mvi - > dma_pool , slot - > buf , slot - > buf_dma ) ;
2011-04-26 17:36:51 +04:00
slot - > buf = NULL ;
}
2009-05-09 01:46:40 +04:00
list_del_init ( & slot - > entry ) ;
2009-05-09 01:44:01 +04:00
task - > lldd_task = NULL ;
slot - > task = NULL ;
slot - > port = NULL ;
2009-05-09 01:46:40 +04:00
slot - > slot_tag = 0xFFFFFFFF ;
mvs_slot_free ( mvi , slot_idx ) ;
2009-05-09 01:44:01 +04:00
}
2011-05-24 18:37:25 +04:00
static void mvs_update_wideport ( struct mvs_info * mvi , int phy_no )
2009-05-09 01:44:01 +04:00
{
2011-05-24 18:37:25 +04:00
struct mvs_phy * phy = & mvi - > phy [ phy_no ] ;
2009-05-09 01:44:01 +04:00
struct mvs_port * port = phy - > port ;
int j , no ;
2009-05-09 01:46:40 +04:00
for_each_phy ( port - > wide_port_phymap , j , no ) {
if ( j & 1 ) {
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , no ,
PHYR_WIDE_PORT ) ;
MVS_CHIP_DISP - > write_port_cfg_data ( mvi , no ,
2009-05-09 01:44:01 +04:00
port - > wide_port_phymap ) ;
} else {
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , no ,
PHYR_WIDE_PORT ) ;
MVS_CHIP_DISP - > write_port_cfg_data ( mvi , no ,
0 ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
}
2009-05-09 01:44:01 +04:00
}
static u32 mvs_is_phy_ready ( struct mvs_info * mvi , int i )
{
u32 tmp ;
struct mvs_phy * phy = & mvi - > phy [ i ] ;
2009-05-09 01:46:40 +04:00
struct mvs_port * port = phy - > port ;
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
tmp = MVS_CHIP_DISP - > read_phy_ctl ( mvi , i ) ;
2009-05-09 01:44:01 +04:00
if ( ( tmp & PHY_READY_MASK ) & & ! ( phy - > irq_status & PHYEV_POOF ) ) {
if ( ! port )
phy - > phy_attached = 1 ;
return tmp ;
}
if ( port ) {
if ( phy - > phy_type & PORT_TYPE_SAS ) {
port - > wide_port_phymap & = ~ ( 1U < < i ) ;
if ( ! port - > wide_port_phymap )
port - > port_attached = 0 ;
mvs_update_wideport ( mvi , i ) ;
} else if ( phy - > phy_type & PORT_TYPE_SATA )
port - > port_attached = 0 ;
phy - > port = NULL ;
phy - > phy_attached = 0 ;
phy - > phy_type & = ~ ( PORT_TYPE_SAS | PORT_TYPE_SATA ) ;
}
return 0 ;
}
static void * mvs_get_d2h_reg ( struct mvs_info * mvi , int i , void * buf )
{
u32 * s = ( u32 * ) buf ;
if ( ! s )
return NULL ;
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , i , PHYR_SATA_SIG3 ) ;
2011-05-24 18:37:25 +04:00
s [ 3 ] = cpu_to_le32 ( MVS_CHIP_DISP - > read_port_cfg_data ( mvi , i ) ) ;
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , i , PHYR_SATA_SIG2 ) ;
2011-05-24 18:37:25 +04:00
s [ 2 ] = cpu_to_le32 ( MVS_CHIP_DISP - > read_port_cfg_data ( mvi , i ) ) ;
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , i , PHYR_SATA_SIG1 ) ;
2011-05-24 18:37:25 +04:00
s [ 1 ] = cpu_to_le32 ( MVS_CHIP_DISP - > read_port_cfg_data ( mvi , i ) ) ;
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , i , PHYR_SATA_SIG0 ) ;
2011-05-24 18:37:25 +04:00
s [ 0 ] = cpu_to_le32 ( MVS_CHIP_DISP - > read_port_cfg_data ( mvi , i ) ) ;
2009-05-09 01:46:40 +04:00
if ( ( ( s [ 1 ] & 0x00FFFFFF ) = = 0x00EB1401 ) & & ( * ( u8 * ) & s [ 3 ] = = 0x01 ) )
s [ 1 ] = 0x00EB1401 | ( * ( ( u8 * ) & s [ 1 ] + 3 ) & 0x10 ) ;
2009-05-09 01:44:01 +04:00
2009-05-15 04:41:21 +04:00
return s ;
2009-05-09 01:44:01 +04:00
}
static u32 mvs_is_sig_fis_received ( u32 irq_status )
{
return irq_status & PHYEV_SIG_FIS ;
}
2011-05-24 18:33:11 +04:00
static void mvs_sig_remove_timer ( struct mvs_phy * phy )
{
if ( phy - > timer . function )
del_timer ( & phy - > timer ) ;
phy - > timer . function = NULL ;
}
2009-05-09 01:46:40 +04:00
void mvs_update_phyinfo ( struct mvs_info * mvi , int i , int get_st )
2009-05-09 01:44:01 +04:00
{
struct mvs_phy * phy = & mvi - > phy [ i ] ;
2009-05-09 01:46:40 +04:00
struct sas_identify_frame * id ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
id = ( struct sas_identify_frame * ) phy - > frame_rcvd ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
if ( get_st ) {
2009-05-09 01:46:40 +04:00
phy - > irq_status = MVS_CHIP_DISP - > read_port_irq_stat ( mvi , i ) ;
2009-05-09 01:44:01 +04:00
phy - > phy_status = mvs_is_phy_ready ( mvi , i ) ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:44:01 +04:00
if ( phy - > phy_status ) {
2009-05-09 01:46:40 +04:00
int oob_done = 0 ;
struct asd_sas_phy * sas_phy = & mvi - > phy [ i ] . sas_phy ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
oob_done = MVS_CHIP_DISP - > oob_done ( mvi , i ) ;
MVS_CHIP_DISP - > fix_phy_info ( mvi , i , id ) ;
if ( phy - > phy_type & PORT_TYPE_SATA ) {
phy - > identify . target_port_protocols = SAS_PROTOCOL_STP ;
if ( mvs_is_sig_fis_received ( phy - > irq_status ) ) {
2011-05-24 18:33:11 +04:00
mvs_sig_remove_timer ( phy ) ;
2009-05-09 01:46:40 +04:00
phy - > phy_attached = 1 ;
phy - > att_dev_sas_addr =
i + mvi - > id * mvi - > chip - > n_phy ;
if ( oob_done )
sas_phy - > oob_mode = SATA_OOB_MODE ;
phy - > frame_rcvd_size =
sizeof ( struct dev_to_host_fis ) ;
2009-05-15 04:41:21 +04:00
mvs_get_d2h_reg ( mvi , i , id ) ;
2009-05-09 01:46:40 +04:00
} else {
u32 tmp ;
dev_printk ( KERN_DEBUG , mvi - > dev ,
" Phy%d : No sig fis \n " , i ) ;
tmp = MVS_CHIP_DISP - > read_port_irq_mask ( mvi , i ) ;
MVS_CHIP_DISP - > write_port_irq_mask ( mvi , i ,
tmp | PHYEV_SIG_FIS ) ;
phy - > phy_attached = 0 ;
phy - > phy_type & = ~ PORT_TYPE_SATA ;
goto out_done ;
}
2010-02-15 09:00:00 +03:00
} else if ( phy - > phy_type & PORT_TYPE_SAS
2009-05-09 01:46:40 +04:00
| | phy - > att_dev_info & PORT_SSP_INIT_MASK ) {
phy - > phy_attached = 1 ;
2009-05-09 01:44:01 +04:00
phy - > identify . device_type =
2009-05-09 01:46:40 +04:00
phy - > att_dev_info & PORT_DEV_TYPE_MASK ;
2007-10-26 04:58:22 +04:00
2013-05-08 01:44:06 +04:00
if ( phy - > identify . device_type = = SAS_END_DEVICE )
2009-05-09 01:44:01 +04:00
phy - > identify . target_port_protocols =
SAS_PROTOCOL_SSP ;
2013-05-08 01:44:06 +04:00
else if ( phy - > identify . device_type ! = SAS_PHY_UNUSED )
2009-05-09 01:44:01 +04:00
phy - > identify . target_port_protocols =
SAS_PROTOCOL_SMP ;
2009-05-09 01:46:40 +04:00
if ( oob_done )
2009-05-09 01:44:01 +04:00
sas_phy - > oob_mode = SAS_OOB_MODE ;
phy - > frame_rcvd_size =
sizeof ( struct sas_identify_frame ) ;
}
2009-05-09 01:46:40 +04:00
memcpy ( sas_phy - > attached_sas_addr ,
& phy - > att_dev_sas_addr , SAS_ADDR_SIZE ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( MVS_CHIP_DISP - > phy_work_around )
MVS_CHIP_DISP - > phy_work_around ( mvi , i ) ;
2009-05-09 01:44:01 +04:00
}
2011-05-24 18:37:25 +04:00
mv_dprintk ( " phy %d attach dev info is %x \n " ,
2009-05-09 01:46:40 +04:00
i + mvi - > id * mvi - > chip - > n_phy , phy - > att_dev_info ) ;
2011-05-24 18:37:25 +04:00
mv_dprintk ( " phy %d attach sas addr is %llx \n " ,
2009-05-09 01:46:40 +04:00
i + mvi - > id * mvi - > chip - > n_phy , phy - > att_dev_sas_addr ) ;
2008-03-27 09:54:50 +03:00
out_done :
2009-05-09 01:44:01 +04:00
if ( get_st )
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > write_port_irq_stat ( mvi , i , phy - > irq_status ) ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
static void mvs_port_notify_formed ( struct asd_sas_phy * sas_phy , int lock )
2008-02-23 16:15:27 +03:00
{
2009-05-09 01:44:01 +04:00
struct sas_ha_struct * sas_ha = sas_phy - > ha ;
2009-05-09 01:46:40 +04:00
struct mvs_info * mvi = NULL ; int i = 0 , hi ;
2009-05-09 01:44:01 +04:00
struct mvs_phy * phy = sas_phy - > lldd_phy ;
2009-05-09 01:46:40 +04:00
struct asd_sas_port * sas_port = sas_phy - > port ;
struct mvs_port * port ;
unsigned long flags = 0 ;
if ( ! sas_port )
return ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
while ( sas_ha - > sas_phy [ i ] ) {
if ( sas_ha - > sas_phy [ i ] = = sas_phy )
break ;
i + + ;
}
hi = i / ( ( struct mvs_prv_info * ) sas_ha - > lldd_ha ) - > n_phy ;
mvi = ( ( struct mvs_prv_info * ) sas_ha - > lldd_ha ) - > mvi [ hi ] ;
2011-05-24 18:37:25 +04:00
if ( i > = mvi - > chip - > n_phy )
port = & mvi - > port [ i - mvi - > chip - > n_phy ] ;
2009-05-09 01:46:40 +04:00
else
2011-05-24 18:37:25 +04:00
port = & mvi - > port [ i ] ;
2009-05-09 01:46:40 +04:00
if ( lock )
spin_lock_irqsave ( & mvi - > lock , flags ) ;
2009-05-09 01:44:01 +04:00
port - > port_attached = 1 ;
phy - > port = port ;
2011-04-26 17:36:51 +04:00
sas_port - > lldd_port = port ;
2009-05-09 01:44:01 +04:00
if ( phy - > phy_type & PORT_TYPE_SAS ) {
port - > wide_port_phymap = sas_port - > phy_mask ;
2009-05-09 01:46:40 +04:00
mv_printk ( " set wide port phy map %x \n " , sas_port - > phy_mask ) ;
2009-05-09 01:44:01 +04:00
mvs_update_wideport ( mvi , sas_phy - > id ) ;
2011-09-29 11:33:49 +04:00
/* direct attached SAS device */
if ( phy - > att_dev_info & PORT_SSP_TRGT_MASK ) {
MVS_CHIP_DISP - > write_port_cfg_addr ( mvi , i , PHYR_PHY_STAT ) ;
MVS_CHIP_DISP - > write_port_cfg_data ( mvi , i , 0x04 ) ;
}
2008-02-23 16:15:27 +03:00
}
2009-05-09 01:46:40 +04:00
if ( lock )
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
static void mvs_port_notify_deformed ( struct asd_sas_phy * sas_phy , int lock )
2009-05-09 01:44:01 +04:00
{
2010-02-15 09:00:00 +03:00
struct domain_device * dev ;
struct mvs_phy * phy = sas_phy - > lldd_phy ;
struct mvs_info * mvi = phy - > mvi ;
struct asd_sas_port * port = sas_phy - > port ;
int phy_no = 0 ;
while ( phy ! = & mvi - > phy [ phy_no ] ) {
phy_no + + ;
if ( phy_no > = MVS_MAX_PHYS )
return ;
}
list_for_each_entry ( dev , & port - > dev_list , dev_list_node )
2011-05-24 18:37:25 +04:00
mvs_do_release_task ( phy - > mvi , phy_no , dev ) ;
2010-02-15 09:00:00 +03:00
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
void mvs_port_formed ( struct asd_sas_phy * sas_phy )
{
mvs_port_notify_formed ( sas_phy , 1 ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
void mvs_port_deformed ( struct asd_sas_phy * sas_phy )
2009-05-09 01:44:01 +04:00
{
2009-05-09 01:46:40 +04:00
mvs_port_notify_deformed ( sas_phy , 1 ) ;
}
2008-02-23 16:15:27 +03:00
2016-09-25 08:48:50 +03:00
static struct mvs_device * mvs_alloc_dev ( struct mvs_info * mvi )
2009-05-09 01:46:40 +04:00
{
u32 dev ;
for ( dev = 0 ; dev < MVS_MAX_DEVICES ; dev + + ) {
2013-05-08 01:44:06 +04:00
if ( mvi - > devices [ dev ] . dev_type = = SAS_PHY_UNUSED ) {
2009-05-09 01:46:40 +04:00
mvi - > devices [ dev ] . device_id = dev ;
return & mvi - > devices [ dev ] ;
}
2008-02-23 16:15:27 +03:00
}
2008-03-27 09:55:04 +03:00
2009-05-09 01:46:40 +04:00
if ( dev = = MVS_MAX_DEVICES )
mv_printk ( " max support %d devices, ignore .. \n " ,
MVS_MAX_DEVICES ) ;
return NULL ;
2008-02-23 16:15:27 +03:00
}
2016-09-25 08:48:50 +03:00
static void mvs_free_dev ( struct mvs_device * mvi_dev )
2007-10-26 04:58:22 +04:00
{
2009-05-09 01:46:40 +04:00
u32 id = mvi_dev - > device_id ;
memset ( mvi_dev , 0 , sizeof ( * mvi_dev ) ) ;
mvi_dev - > device_id = id ;
2013-05-08 01:44:06 +04:00
mvi_dev - > dev_type = SAS_PHY_UNUSED ;
2009-05-09 01:46:40 +04:00
mvi_dev - > dev_status = MVS_DEV_NORMAL ;
mvi_dev - > taskfileset = MVS_ID_NOT_MAPPED ;
}
2007-10-26 04:58:22 +04:00
2016-09-25 08:48:50 +03:00
static int mvs_dev_found_notify ( struct domain_device * dev , int lock )
2009-05-09 01:46:40 +04:00
{
unsigned long flags = 0 ;
int res = 0 ;
struct mvs_info * mvi = NULL ;
struct domain_device * parent_dev = dev - > parent ;
struct mvs_device * mvi_device ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
mvi = mvs_find_dev_mvi ( dev ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( lock )
spin_lock_irqsave ( & mvi - > lock , flags ) ;
mvi_device = mvs_alloc_dev ( mvi ) ;
if ( ! mvi_device ) {
res = - 1 ;
goto found_out ;
2007-10-26 04:58:22 +04:00
}
2009-05-15 04:41:21 +04:00
dev - > lldd_dev = mvi_device ;
2010-02-15 09:00:00 +03:00
mvi_device - > dev_status = MVS_DEV_NORMAL ;
2009-05-09 01:46:40 +04:00
mvi_device - > dev_type = dev - > dev_type ;
2009-05-11 18:19:25 +04:00
mvi_device - > mvi_info = mvi ;
2011-05-24 18:37:25 +04:00
mvi_device - > sas_device = dev ;
2009-05-09 01:46:40 +04:00
if ( parent_dev & & DEV_IS_EXPANDER ( parent_dev - > dev_type ) ) {
int phy_id ;
u8 phy_num = parent_dev - > ex_dev . num_phys ;
struct ex_phy * phy ;
for ( phy_id = 0 ; phy_id < phy_num ; phy_id + + ) {
phy = & parent_dev - > ex_dev . ex_phy [ phy_id ] ;
if ( SAS_ADDR ( phy - > attached_sas_addr ) = =
SAS_ADDR ( dev - > sas_addr ) ) {
mvi_device - > attached_phy = phy_id ;
break ;
}
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( phy_id = = phy_num ) {
mv_printk ( " Error: no attached dev:%016llx "
" at ex:%016llx. \n " ,
SAS_ADDR ( dev - > sas_addr ) ,
SAS_ADDR ( parent_dev - > sas_addr ) ) ;
res = - 1 ;
}
2009-05-09 01:44:01 +04:00
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
found_out :
if ( lock )
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
return res ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
int mvs_dev_found ( struct domain_device * dev )
{
return mvs_dev_found_notify ( dev , 1 ) ;
}
2007-10-26 04:58:22 +04:00
2016-09-25 08:48:50 +03:00
static void mvs_dev_gone_notify ( struct domain_device * dev )
2009-05-09 01:46:40 +04:00
{
unsigned long flags = 0 ;
2009-05-15 04:41:21 +04:00
struct mvs_device * mvi_dev = dev - > lldd_dev ;
2014-05-18 20:12:26 +04:00
struct mvs_info * mvi ;
2007-10-26 04:58:22 +04:00
2014-05-18 20:12:26 +04:00
if ( ! mvi_dev ) {
2009-05-09 01:46:40 +04:00
mv_dprintk ( " found dev has gone. \n " ) ;
2014-05-18 20:12:26 +04:00
return ;
2007-10-26 04:58:22 +04:00
}
2014-05-18 20:12:26 +04:00
mvi = mvi_dev - > mvi_info ;
spin_lock_irqsave ( & mvi - > lock , flags ) ;
mv_dprintk ( " found dev[%d:%x] is gone. \n " ,
mvi_dev - > device_id , mvi_dev - > dev_type ) ;
mvs_release_task ( mvi , dev ) ;
mvs_free_reg_set ( mvi , mvi_dev ) ;
mvs_free_dev ( mvi_dev ) ;
2009-05-09 01:46:40 +04:00
dev - > lldd_dev = NULL ;
2011-05-24 18:37:25 +04:00
mvi_dev - > sas_device = NULL ;
2007-10-26 04:58:22 +04:00
2010-02-15 09:00:00 +03:00
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
void mvs_dev_gone ( struct domain_device * dev )
{
2010-02-15 09:00:00 +03:00
mvs_dev_gone_notify ( dev ) ;
2009-05-09 01:46:40 +04:00
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
static void mvs_task_done ( struct sas_task * task )
{
2012-06-22 10:36:30 +04:00
if ( ! del_timer ( & task - > slow_task - > timer ) )
2009-05-09 01:46:40 +04:00
return ;
2012-06-22 10:36:30 +04:00
complete ( & task - > slow_task - > completion ) ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
static void mvs_tmf_timedout ( unsigned long data )
2007-10-26 04:58:22 +04:00
{
2009-05-09 01:46:40 +04:00
struct sas_task * task = ( struct sas_task * ) data ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
task - > task_state_flags | = SAS_TASK_STATE_ABORTED ;
2012-06-22 10:36:30 +04:00
complete ( & task - > slow_task - > completion ) ;
2009-05-09 01:46:40 +04:00
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
# define MVS_TASK_TIMEOUT 20
static int mvs_exec_internal_tmf_task ( struct domain_device * dev ,
void * parameter , u32 para_len , struct mvs_tmf_task * tmf )
{
int res , retry ;
struct sas_task * task = NULL ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
for ( retry = 0 ; retry < 3 ; retry + + ) {
2012-06-22 10:36:30 +04:00
task = sas_alloc_slow_task ( GFP_KERNEL ) ;
2009-05-09 01:46:40 +04:00
if ( ! task )
return - ENOMEM ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
task - > dev = dev ;
task - > task_proto = dev - > tproto ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
memcpy ( & task - > ssp_task , parameter , para_len ) ;
task - > task_done = mvs_task_done ;
2008-02-23 16:15:27 +03:00
2012-06-22 10:36:30 +04:00
task - > slow_task - > timer . data = ( unsigned long ) task ;
task - > slow_task - > timer . function = mvs_tmf_timedout ;
task - > slow_task - > timer . expires = jiffies + MVS_TASK_TIMEOUT * HZ ;
add_timer ( & task - > slow_task - > timer ) ;
2008-02-23 16:15:27 +03:00
2014-11-05 12:36:28 +03:00
res = mvs_task_exec ( task , GFP_KERNEL , NULL , 1 , tmf ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
if ( res ) {
2012-06-22 10:36:30 +04:00
del_timer ( & task - > slow_task - > timer ) ;
2013-09-30 18:19:09 +04:00
mv_printk ( " executing internal task failed:%d \n " , res ) ;
2009-05-09 01:46:40 +04:00
goto ex_err ;
}
2008-02-23 16:15:27 +03:00
2012-06-22 10:36:30 +04:00
wait_for_completion ( & task - > slow_task - > completion ) ;
2011-05-24 18:37:25 +04:00
res = TMF_RESP_FUNC_FAILED ;
2009-05-09 01:46:40 +04:00
/* Even TMF timed out, return direct. */
if ( ( task - > task_state_flags & SAS_TASK_STATE_ABORTED ) ) {
if ( ! ( task - > task_state_flags & SAS_TASK_STATE_DONE ) ) {
mv_printk ( " TMF task[%x] timeout. \n " , tmf - > tmf ) ;
goto ex_err ;
}
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
if ( task - > task_status . resp = = SAS_TASK_COMPLETE & &
2010-07-28 00:51:13 +04:00
task - > task_status . stat = = SAM_STAT_GOOD ) {
2009-05-09 01:46:40 +04:00
res = TMF_RESP_FUNC_COMPLETE ;
break ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( task - > task_status . resp = = SAS_TASK_COMPLETE & &
task - > task_status . stat = = SAS_DATA_UNDERRUN ) {
/* no error, but return the number of bytes of
* underrun */
res = task - > task_status . residual ;
break ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( task - > task_status . resp = = SAS_TASK_COMPLETE & &
task - > task_status . stat = = SAS_DATA_OVERRUN ) {
mv_dprintk ( " blocked task error. \n " ) ;
res = - EMSGSIZE ;
break ;
} else {
mv_dprintk ( " task to dev %016llx response: 0x%x "
" status 0x%x \n " ,
SAS_ADDR ( dev - > sas_addr ) ,
task - > task_status . resp ,
task - > task_status . stat ) ;
2011-07-30 04:26:39 +04:00
sas_free_task ( task ) ;
2009-05-09 01:46:40 +04:00
task = NULL ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:44:01 +04:00
}
}
2009-05-09 01:46:40 +04:00
ex_err :
BUG_ON ( retry = = 3 & & task ! = NULL ) ;
2011-07-30 04:26:39 +04:00
sas_free_task ( task ) ;
2009-05-09 01:46:40 +04:00
return res ;
2009-05-09 01:44:01 +04:00
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
static int mvs_debug_issue_ssp_tmf ( struct domain_device * dev ,
u8 * lun , struct mvs_tmf_task * tmf )
2009-05-09 01:44:01 +04:00
{
2009-05-09 01:46:40 +04:00
struct sas_ssp_task ssp_task ;
if ( ! ( dev - > tproto & SAS_PROTOCOL_SSP ) )
return TMF_RESP_FUNC_ESUPP ;
2007-10-26 04:58:22 +04:00
2011-05-24 18:37:25 +04:00
memcpy ( ssp_task . LUN , lun , 8 ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
return mvs_exec_internal_tmf_task ( dev , & ssp_task ,
sizeof ( ssp_task ) , tmf ) ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
/* Standard mandates link reset for ATA (type 0)
and hard reset for SSP ( type 1 ) , only for RECOVERY */
static int mvs_debug_I_T_nexus_reset ( struct domain_device * dev )
{
int rc ;
2011-12-22 09:33:17 +04:00
struct sas_phy * phy = sas_get_local_phy ( dev ) ;
2013-05-08 01:44:06 +04:00
int reset_type = ( dev - > dev_type = = SAS_SATA_DEV | |
2009-05-09 01:46:40 +04:00
( dev - > tproto & SAS_PROTOCOL_STP ) ) ? 0 : 1 ;
rc = sas_phy_reset ( phy , reset_type ) ;
2011-12-22 09:33:17 +04:00
sas_put_local_phy ( phy ) ;
2009-05-09 01:46:40 +04:00
msleep ( 2000 ) ;
return rc ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
/* mandatory SAM-3 */
int mvs_lu_reset ( struct domain_device * dev , u8 * lun )
{
unsigned long flags ;
2011-05-24 18:37:25 +04:00
int rc = TMF_RESP_FUNC_FAILED ;
2009-05-09 01:46:40 +04:00
struct mvs_tmf_task tmf_task ;
2009-05-15 04:41:21 +04:00
struct mvs_device * mvi_dev = dev - > lldd_dev ;
2009-05-11 18:19:25 +04:00
struct mvs_info * mvi = mvi_dev - > mvi_info ;
2009-05-09 01:46:40 +04:00
tmf_task . tmf = TMF_LU_RESET ;
mvi_dev - > dev_status = MVS_DEV_EH ;
rc = mvs_debug_issue_ssp_tmf ( dev , lun , & tmf_task ) ;
if ( rc = = TMF_RESP_FUNC_COMPLETE ) {
spin_lock_irqsave ( & mvi - > lock , flags ) ;
2011-05-24 18:37:25 +04:00
mvs_release_task ( mvi , dev ) ;
2009-05-09 01:46:40 +04:00
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
/* If failed, fall-through I_T_Nexus reset */
mv_printk ( " %s for device[%x]:rc= %d \n " , __func__ ,
mvi_dev - > device_id , rc ) ;
return rc ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
int mvs_I_T_nexus_reset ( struct domain_device * dev )
{
unsigned long flags ;
2010-02-15 09:00:00 +03:00
int rc = TMF_RESP_FUNC_FAILED ;
struct mvs_device * mvi_dev = ( struct mvs_device * ) dev - > lldd_dev ;
2009-05-11 18:19:25 +04:00
struct mvs_info * mvi = mvi_dev - > mvi_info ;
2009-05-09 01:46:40 +04:00
if ( mvi_dev - > dev_status ! = MVS_DEV_EH )
return TMF_RESP_FUNC_COMPLETE ;
2011-05-24 18:37:25 +04:00
else
mvi_dev - > dev_status = MVS_DEV_NORMAL ;
2009-05-09 01:46:40 +04:00
rc = mvs_debug_I_T_nexus_reset ( dev ) ;
mv_printk ( " %s for device[%x]:rc= %d \n " ,
__func__ , mvi_dev - > device_id , rc ) ;
spin_lock_irqsave ( & mvi - > lock , flags ) ;
2010-02-15 09:00:00 +03:00
mvs_release_task ( mvi , dev ) ;
2009-05-09 01:46:40 +04:00
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
return rc ;
}
/* optional SAM-3 */
int mvs_query_task ( struct sas_task * task )
{
u32 tag ;
struct scsi_lun lun ;
struct mvs_tmf_task tmf_task ;
int rc = TMF_RESP_FUNC_FAILED ;
if ( task - > lldd_task & & task - > task_proto & SAS_PROTOCOL_SSP ) {
struct scsi_cmnd * cmnd = ( struct scsi_cmnd * ) task - > uldd_task ;
struct domain_device * dev = task - > dev ;
2009-05-11 18:19:25 +04:00
struct mvs_device * mvi_dev = ( struct mvs_device * ) dev - > lldd_dev ;
struct mvs_info * mvi = mvi_dev - > mvi_info ;
2009-05-09 01:46:40 +04:00
int_to_scsilun ( cmnd - > device - > lun , & lun ) ;
rc = mvs_find_tag ( mvi , task , & tag ) ;
if ( rc = = 0 ) {
rc = TMF_RESP_FUNC_FAILED ;
2009-05-09 01:44:01 +04:00
return rc ;
2009-05-09 01:46:40 +04:00
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
tmf_task . tmf = TMF_QUERY_TASK ;
tmf_task . tag_of_task_to_be_managed = cpu_to_le16 ( tag ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
rc = mvs_debug_issue_ssp_tmf ( dev , lun . scsi_lun , & tmf_task ) ;
switch ( rc ) {
/* The task is still in Lun, release it then */
case TMF_RESP_FUNC_SUCC :
/* The task is not in Lun or failed, reset the phy */
case TMF_RESP_FUNC_FAILED :
case TMF_RESP_FUNC_COMPLETE :
break ;
}
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
mv_printk ( " %s:rc= %d \n " , __func__ , rc ) ;
return rc ;
2008-02-23 16:15:27 +03:00
}
2009-05-09 01:46:40 +04:00
/* mandatory SAM-3, still need free task/slot info */
int mvs_abort_task ( struct sas_task * task )
2008-02-23 16:15:27 +03:00
{
2009-05-09 01:46:40 +04:00
struct scsi_lun lun ;
struct mvs_tmf_task tmf_task ;
struct domain_device * dev = task - > dev ;
2009-05-11 18:19:25 +04:00
struct mvs_device * mvi_dev = ( struct mvs_device * ) dev - > lldd_dev ;
2010-06-22 15:42:02 +04:00
struct mvs_info * mvi ;
2009-05-09 01:46:40 +04:00
int rc = TMF_RESP_FUNC_FAILED ;
unsigned long flags ;
u32 tag ;
2009-05-11 18:19:25 +04:00
2010-02-15 09:00:00 +03:00
if ( ! mvi_dev ) {
2011-05-24 18:37:25 +04:00
mv_printk ( " Device has removed \n " ) ;
return TMF_RESP_FUNC_FAILED ;
2010-02-15 09:00:00 +03:00
}
2010-06-22 15:42:02 +04:00
mvi = mvi_dev - > mvi_info ;
2009-05-09 01:46:40 +04:00
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
if ( task - > task_state_flags & SAS_TASK_STATE_DONE ) {
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
rc = TMF_RESP_FUNC_COMPLETE ;
goto out ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
2010-02-15 09:00:00 +03:00
mvi_dev - > dev_status = MVS_DEV_EH ;
2009-05-09 01:46:40 +04:00
if ( task - > lldd_task & & task - > task_proto & SAS_PROTOCOL_SSP ) {
struct scsi_cmnd * cmnd = ( struct scsi_cmnd * ) task - > uldd_task ;
int_to_scsilun ( cmnd - > device - > lun , & lun ) ;
rc = mvs_find_tag ( mvi , task , & tag ) ;
if ( rc = = 0 ) {
mv_printk ( " No such tag in %s \n " , __func__ ) ;
rc = TMF_RESP_FUNC_FAILED ;
return rc ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
tmf_task . tmf = TMF_ABORT_TASK ;
tmf_task . tag_of_task_to_be_managed = cpu_to_le16 ( tag ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
rc = mvs_debug_issue_ssp_tmf ( dev , lun . scsi_lun , & tmf_task ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
/* if successful, clear the task and callback forwards.*/
if ( rc = = TMF_RESP_FUNC_COMPLETE ) {
u32 slot_no ;
struct mvs_slot_info * slot ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
if ( task - > lldd_task ) {
2009-05-15 04:41:21 +04:00
slot = task - > lldd_task ;
2009-05-09 01:46:40 +04:00
slot_no = ( u32 ) ( slot - mvi - > slot_info ) ;
2010-02-15 09:00:00 +03:00
spin_lock_irqsave ( & mvi - > lock , flags ) ;
2009-05-09 01:46:40 +04:00
mvs_slot_complete ( mvi , slot_no , 1 ) ;
2010-02-15 09:00:00 +03:00
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
2009-05-09 01:46:40 +04:00
}
}
2010-02-15 09:00:00 +03:00
2009-05-09 01:46:40 +04:00
} else if ( task - > task_proto & SAS_PROTOCOL_SATA | |
task - > task_proto & SAS_PROTOCOL_STP ) {
2013-05-08 01:44:06 +04:00
if ( SAS_SATA_DEV = = dev - > dev_type ) {
2010-02-15 09:00:00 +03:00
struct mvs_slot_info * slot = task - > lldd_task ;
u32 slot_idx = ( u32 ) ( slot - mvi - > slot_info ) ;
2011-05-24 18:37:25 +04:00
mv_dprintk ( " mvs_abort_task() mvi=%p task=%p "
2010-02-15 09:00:00 +03:00
" slot=%p slot_idx=x%x \n " ,
mvi , task , slot , slot_idx ) ;
2012-08-04 06:34:14 +04:00
task - > task_state_flags | = SAS_TASK_STATE_ABORTED ;
2010-02-15 09:00:00 +03:00
mvs_slot_task_free ( mvi , task , slot , slot_idx ) ;
2011-05-24 18:37:25 +04:00
rc = TMF_RESP_FUNC_COMPLETE ;
goto out ;
2010-02-15 09:00:00 +03:00
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
}
out :
if ( rc ! = TMF_RESP_FUNC_COMPLETE )
mv_printk ( " %s:rc= %d \n " , __func__ , rc ) ;
2009-05-09 01:44:01 +04:00
return rc ;
2008-02-23 16:15:27 +03:00
}
2009-05-09 01:46:40 +04:00
int mvs_abort_task_set ( struct domain_device * dev , u8 * lun )
2008-02-23 16:15:27 +03:00
{
2009-05-09 01:46:40 +04:00
int rc = TMF_RESP_FUNC_FAILED ;
struct mvs_tmf_task tmf_task ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
tmf_task . tmf = TMF_ABORT_TASK_SET ;
rc = mvs_debug_issue_ssp_tmf ( dev , lun , & tmf_task ) ;
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
return rc ;
2008-02-23 16:15:27 +03:00
}
2009-05-09 01:46:40 +04:00
int mvs_clear_aca ( struct domain_device * dev , u8 * lun )
2008-02-23 16:15:27 +03:00
{
2009-05-09 01:46:40 +04:00
int rc = TMF_RESP_FUNC_FAILED ;
struct mvs_tmf_task tmf_task ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
tmf_task . tmf = TMF_CLEAR_ACA ;
rc = mvs_debug_issue_ssp_tmf ( dev , lun , & tmf_task ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
return rc ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
int mvs_clear_task_set ( struct domain_device * dev , u8 * lun )
{
int rc = TMF_RESP_FUNC_FAILED ;
struct mvs_tmf_task tmf_task ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
tmf_task . tmf = TMF_CLEAR_TASK_SET ;
rc = mvs_debug_issue_ssp_tmf ( dev , lun , & tmf_task ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
return rc ;
2009-05-09 01:44:01 +04:00
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
static int mvs_sata_done ( struct mvs_info * mvi , struct sas_task * task ,
u32 slot_idx , int err )
2009-05-09 01:44:01 +04:00
{
2009-05-15 04:41:21 +04:00
struct mvs_device * mvi_dev = task - > dev - > lldd_dev ;
2009-05-09 01:46:40 +04:00
struct task_status_struct * tstat = & task - > task_status ;
struct ata_task_resp * resp = ( struct ata_task_resp * ) tstat - > buf ;
2010-07-28 00:51:13 +04:00
int stat = SAM_STAT_GOOD ;
2008-03-27 09:55:33 +03:00
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
resp - > frame_len = sizeof ( struct dev_to_host_fis ) ;
memcpy ( & resp - > ending_fis [ 0 ] ,
SATA_RECEIVED_D2H_FIS ( mvi_dev - > taskfileset ) ,
sizeof ( struct dev_to_host_fis ) ) ;
tstat - > buf_valid_size = sizeof ( * resp ) ;
2010-02-15 09:00:00 +03:00
if ( unlikely ( err ) ) {
if ( unlikely ( err & CMD_ISS_STPD ) )
stat = SAS_OPEN_REJECT ;
else
stat = SAS_PROTO_RESPONSE ;
}
2009-05-09 01:46:40 +04:00
return stat ;
2008-02-23 16:15:27 +03:00
}
2016-09-25 08:48:50 +03:00
static void mvs_set_sense ( u8 * buffer , int len , int d_sense ,
2011-05-24 18:36:02 +04:00
int key , int asc , int ascq )
{
memset ( buffer , 0 , len ) ;
if ( d_sense ) {
/* Descriptor format */
if ( len < 4 ) {
mv_printk ( " Length %d of sense buffer too small to "
" fit sense %x:%x:%x " , len , key , asc , ascq ) ;
}
buffer [ 0 ] = 0x72 ; /* Response Code */
if ( len > 1 )
buffer [ 1 ] = key ; /* Sense Key */
if ( len > 2 )
buffer [ 2 ] = asc ; /* ASC */
if ( len > 3 )
buffer [ 3 ] = ascq ; /* ASCQ */
} else {
if ( len < 14 ) {
mv_printk ( " Length %d of sense buffer too small to "
" fit sense %x:%x:%x " , len , key , asc , ascq ) ;
}
buffer [ 0 ] = 0x70 ; /* Response Code */
if ( len > 2 )
buffer [ 2 ] = key ; /* Sense Key */
if ( len > 7 )
buffer [ 7 ] = 0x0a ; /* Additional Sense Length */
if ( len > 12 )
buffer [ 12 ] = asc ; /* ASC */
if ( len > 13 )
buffer [ 13 ] = ascq ; /* ASCQ */
}
return ;
}
2016-09-25 08:48:50 +03:00
static void mvs_fill_ssp_resp_iu ( struct ssp_response_iu * iu ,
2011-05-24 18:36:02 +04:00
u8 key , u8 asc , u8 asc_q )
{
iu - > datapres = 2 ;
iu - > response_data_len = 0 ;
iu - > sense_data_len = 17 ;
iu - > status = 02 ;
mvs_set_sense ( iu - > sense_data , 17 , 0 ,
key , asc , asc_q ) ;
}
2009-05-09 01:46:40 +04:00
static int mvs_slot_err ( struct mvs_info * mvi , struct sas_task * task ,
u32 slot_idx )
2008-02-23 16:15:27 +03:00
{
2009-05-09 01:46:40 +04:00
struct mvs_slot_info * slot = & mvi - > slot_info [ slot_idx ] ;
int stat ;
2011-05-24 18:37:25 +04:00
u32 err_dw0 = le32_to_cpu ( * ( u32 * ) slot - > response ) ;
2011-05-24 18:36:02 +04:00
u32 err_dw1 = le32_to_cpu ( * ( ( u32 * ) slot - > response + 1 ) ) ;
2009-05-09 01:46:40 +04:00
u32 tfs = 0 ;
enum mvs_port_type type = PORT_TYPE_SAS ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
if ( err_dw0 & CMD_ISS_STPD )
MVS_CHIP_DISP - > issue_stop ( mvi , type , tfs ) ;
MVS_CHIP_DISP - > command_active ( mvi , slot_idx ) ;
2007-10-26 04:58:22 +04:00
2010-07-28 00:51:13 +04:00
stat = SAM_STAT_CHECK_CONDITION ;
2009-05-09 01:44:01 +04:00
switch ( task - > task_proto ) {
case SAS_PROTOCOL_SSP :
2011-05-24 18:36:02 +04:00
{
2009-05-09 01:46:40 +04:00
stat = SAS_ABORTED_TASK ;
2011-05-24 18:36:02 +04:00
if ( ( err_dw0 & NO_DEST ) | | err_dw1 & bit ( 31 ) ) {
struct ssp_response_iu * iu = slot - > response +
sizeof ( struct mvs_err_info ) ;
mvs_fill_ssp_resp_iu ( iu , NOT_READY , 0x04 , 01 ) ;
sas_ssp_task_response ( mvi - > dev , task , iu ) ;
stat = SAM_STAT_CHECK_CONDITION ;
}
if ( err_dw1 & bit ( 31 ) )
mv_printk ( " reuse same slot, retry command. \n " ) ;
2009-05-09 01:46:40 +04:00
break ;
2011-05-24 18:36:02 +04:00
}
2009-05-09 01:46:40 +04:00
case SAS_PROTOCOL_SMP :
2010-07-28 00:51:13 +04:00
stat = SAM_STAT_CHECK_CONDITION ;
2009-05-09 01:44:01 +04:00
break ;
2009-05-09 01:46:40 +04:00
2009-05-09 01:44:01 +04:00
case SAS_PROTOCOL_SATA :
case SAS_PROTOCOL_STP :
2009-05-09 01:46:40 +04:00
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP :
{
task - > ata_task . use_ncq = 0 ;
2011-05-24 18:37:25 +04:00
stat = SAS_PROTO_RESPONSE ;
2010-02-15 09:00:00 +03:00
mvs_sata_done ( mvi , task , slot_idx , err_dw0 ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
break ;
2009-05-09 01:44:01 +04:00
default :
break ;
}
2009-05-09 01:46:40 +04:00
return stat ;
2008-03-27 09:55:33 +03:00
}
2009-05-09 01:46:40 +04:00
int mvs_slot_complete ( struct mvs_info * mvi , u32 rx_desc , u32 flags )
2007-10-26 04:58:22 +04:00
{
2009-05-09 01:46:40 +04:00
u32 slot_idx = rx_desc & RXQ_SLOT_MASK ;
struct mvs_slot_info * slot = & mvi - > slot_info [ slot_idx ] ;
struct sas_task * task = slot - > task ;
struct mvs_device * mvi_dev = NULL ;
struct task_status_struct * tstat ;
2010-02-15 09:00:00 +03:00
struct domain_device * dev ;
u32 aborted ;
2009-05-09 01:46:40 +04:00
void * to ;
enum exec_status sts ;
2010-02-15 09:00:00 +03:00
if ( unlikely ( ! task | | ! task - > lldd_task | | ! task - > dev ) )
2009-05-09 01:46:40 +04:00
return - 1 ;
tstat = & task - > task_status ;
2010-02-15 09:00:00 +03:00
dev = task - > dev ;
mvi_dev = dev - > lldd_dev ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
spin_lock ( & task - > task_state_lock ) ;
task - > task_state_flags & =
~ ( SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR ) ;
task - > task_state_flags | = SAS_TASK_STATE_DONE ;
/* race condition*/
aborted = task - > task_state_flags & SAS_TASK_STATE_ABORTED ;
spin_unlock ( & task - > task_state_lock ) ;
memset ( tstat , 0 , sizeof ( * tstat ) ) ;
tstat - > resp = SAS_TASK_COMPLETE ;
if ( unlikely ( aborted ) ) {
tstat - > stat = SAS_ABORTED_TASK ;
2010-02-15 09:00:00 +03:00
if ( mvi_dev & & mvi_dev - > running_req )
mvi_dev - > running_req - - ;
2009-05-09 01:46:40 +04:00
if ( sas_protocol_ata ( task - > task_proto ) )
mvs_free_reg_set ( mvi , mvi_dev ) ;
mvs_slot_task_free ( mvi , task , slot , slot_idx ) ;
return - 1 ;
2007-10-26 04:58:22 +04:00
}
2011-05-24 18:38:10 +04:00
/* when no device attaching, go ahead and complete by error handling*/
2010-02-15 09:00:00 +03:00
if ( unlikely ( ! mvi_dev | | flags ) ) {
if ( ! mvi_dev )
mv_dprintk ( " port has not device. \n " ) ;
2009-05-09 01:46:40 +04:00
tstat - > stat = SAS_PHY_DOWN ;
goto out ;
}
2007-10-26 04:58:22 +04:00
2013-06-09 20:23:16 +04:00
/*
* error info record present ; slot - > response is 32 bit aligned but may
* not be 64 bit aligned , so check for zero in two 32 bit reads
*/
if ( unlikely ( ( rx_desc & RXQ_ERR )
& & ( * ( ( u32 * ) slot - > response )
| | * ( ( ( u32 * ) slot - > response ) + 1 ) ) ) ) {
2011-05-24 18:37:25 +04:00
mv_dprintk ( " port %d slot %d rx_desc %X has error info "
" %016llX. \n " , slot - > port - > sas_port . id , slot_idx ,
2013-06-09 20:23:16 +04:00
rx_desc , get_unaligned_le64 ( slot - > response ) ) ;
2009-05-09 01:46:40 +04:00
tstat - > stat = mvs_slot_err ( mvi , task , slot_idx ) ;
2010-02-15 09:00:00 +03:00
tstat - > resp = SAS_TASK_COMPLETE ;
2009-05-09 01:46:40 +04:00
goto out ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
switch ( task - > task_proto ) {
case SAS_PROTOCOL_SSP :
/* hw says status == 0, datapres == 0 */
if ( rx_desc & RXQ_GOOD ) {
2010-07-28 00:51:13 +04:00
tstat - > stat = SAM_STAT_GOOD ;
2009-05-09 01:46:40 +04:00
tstat - > resp = SAS_TASK_COMPLETE ;
}
/* response frame present */
else if ( rx_desc & RXQ_RSP ) {
struct ssp_response_iu * iu = slot - > response +
sizeof ( struct mvs_err_info ) ;
sas_ssp_task_response ( mvi - > dev , task , iu ) ;
} else
2010-07-28 00:51:13 +04:00
tstat - > stat = SAM_STAT_CHECK_CONDITION ;
2009-05-09 01:46:40 +04:00
break ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
case SAS_PROTOCOL_SMP : {
struct scatterlist * sg_resp = & task - > smp_task . smp_resp ;
2010-07-28 00:51:13 +04:00
tstat - > stat = SAM_STAT_GOOD ;
2011-11-25 19:14:23 +04:00
to = kmap_atomic ( sg_page ( sg_resp ) ) ;
2009-05-09 01:46:40 +04:00
memcpy ( to + sg_resp - > offset ,
slot - > response + sizeof ( struct mvs_err_info ) ,
sg_dma_len ( sg_resp ) ) ;
2011-11-25 19:14:23 +04:00
kunmap_atomic ( to ) ;
2009-05-09 01:46:40 +04:00
break ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
case SAS_PROTOCOL_SATA :
case SAS_PROTOCOL_STP :
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP : {
tstat - > stat = mvs_sata_done ( mvi , task , slot_idx , 0 ) ;
break ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
default :
2010-07-28 00:51:13 +04:00
tstat - > stat = SAM_STAT_CHECK_CONDITION ;
2009-05-09 01:46:40 +04:00
break ;
}
2010-02-15 09:00:00 +03:00
if ( ! slot - > port - > port_attached ) {
mv_dprintk ( " port %d has removed. \n " , slot - > port - > sas_port . id ) ;
tstat - > stat = SAS_PHY_DOWN ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
out :
2010-02-15 09:00:00 +03:00
if ( mvi_dev & & mvi_dev - > running_req ) {
mvi_dev - > running_req - - ;
if ( sas_protocol_ata ( task - > task_proto ) & & ! mvi_dev - > running_req )
2009-05-11 17:49:52 +04:00
mvs_free_reg_set ( mvi , mvi_dev ) ;
}
2009-05-09 01:46:40 +04:00
mvs_slot_task_free ( mvi , task , slot , slot_idx ) ;
sts = tstat - > stat ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
spin_unlock ( & mvi - > lock ) ;
if ( task - > task_done )
task - > task_done ( task ) ;
2011-05-24 18:37:25 +04:00
2009-05-09 01:46:40 +04:00
spin_lock ( & mvi - > lock ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
return sts ;
}
2007-10-26 04:58:22 +04:00
2010-02-15 09:00:00 +03:00
void mvs_do_release_task ( struct mvs_info * mvi ,
2009-05-09 01:46:40 +04:00
int phy_no , struct domain_device * dev )
{
2010-02-15 09:00:00 +03:00
u32 slot_idx ;
2009-05-09 01:46:40 +04:00
struct mvs_phy * phy ;
struct mvs_port * port ;
struct mvs_slot_info * slot , * slot2 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
phy = & mvi - > phy [ phy_no ] ;
port = phy - > port ;
if ( ! port )
return ;
2010-02-15 09:00:00 +03:00
/* clean cmpl queue in case request is already finished */
mvs_int_rx ( mvi , false ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
list_for_each_entry_safe ( slot , slot2 , & port - > list , entry ) {
struct sas_task * task ;
slot_idx = ( u32 ) ( slot - mvi - > slot_info ) ;
task = slot - > task ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( dev & & task - > dev ! = dev )
continue ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
mv_printk ( " Release slot [%x] tag[%x], task [%p]: \n " ,
slot_idx , slot - > slot_tag , task ) ;
2010-02-15 09:00:00 +03:00
MVS_CHIP_DISP - > command_active ( mvi , slot_idx ) ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
mvs_slot_complete ( mvi , slot_idx , 1 ) ;
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
}
2007-10-26 04:58:22 +04:00
2010-02-15 09:00:00 +03:00
void mvs_release_task ( struct mvs_info * mvi ,
struct domain_device * dev )
{
int i , phyno [ WIDE_PORT_MAX_PHY ] , num ;
num = mvs_find_dev_phyno ( dev , phyno ) ;
for ( i = 0 ; i < num ; i + + )
mvs_do_release_task ( mvi , phyno [ i ] , dev ) ;
}
2009-05-09 01:46:40 +04:00
static void mvs_phy_disconnected ( struct mvs_phy * phy )
{
phy - > phy_attached = 0 ;
phy - > att_dev_info = 0 ;
phy - > att_dev_sas_addr = 0 ;
}
static void mvs_work_queue ( struct work_struct * work )
{
struct delayed_work * dw = container_of ( work , struct delayed_work , work ) ;
struct mvs_wq * mwq = container_of ( dw , struct mvs_wq , work_q ) ;
struct mvs_info * mvi = mwq - > mvi ;
unsigned long flags ;
2011-05-24 18:36:02 +04:00
u32 phy_no = ( unsigned long ) mwq - > data ;
struct sas_ha_struct * sas_ha = mvi - > sas ;
struct mvs_phy * phy = & mvi - > phy [ phy_no ] ;
struct asd_sas_phy * sas_phy = & phy - > sas_phy ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
spin_lock_irqsave ( & mvi - > lock , flags ) ;
if ( mwq - > handler & PHY_PLUG_EVENT ) {
if ( phy - > phy_event & PHY_PLUG_OUT ) {
u32 tmp ;
struct sas_identify_frame * id ;
id = ( struct sas_identify_frame * ) phy - > frame_rcvd ;
tmp = MVS_CHIP_DISP - > read_phy_ctl ( mvi , phy_no ) ;
phy - > phy_event & = ~ PHY_PLUG_OUT ;
if ( ! ( tmp & PHY_READY_MASK ) ) {
sas_phy_disconnected ( sas_phy ) ;
mvs_phy_disconnected ( phy ) ;
sas_ha - > notify_phy_event ( sas_phy ,
PHYE_LOSS_OF_SIGNAL ) ;
mv_dprintk ( " phy%d Removed Device \n " , phy_no ) ;
} else {
MVS_CHIP_DISP - > detect_porttype ( mvi , phy_no ) ;
mvs_update_phyinfo ( mvi , phy_no , 1 ) ;
mvs_bytes_dmaed ( mvi , phy_no ) ;
mvs_port_notify_formed ( sas_phy , 0 ) ;
mv_dprintk ( " phy%d Attached Device \n " , phy_no ) ;
}
}
2011-05-24 18:36:02 +04:00
} else if ( mwq - > handler & EXP_BRCT_CHG ) {
phy - > phy_event & = ~ EXP_BRCT_CHG ;
sas_ha - > notify_port_event ( sas_phy ,
PORTE_BROADCAST_RCVD ) ;
mv_dprintk ( " phy%d Got Broadcast Change \n " , phy_no ) ;
2009-05-09 01:46:40 +04:00
}
list_del ( & mwq - > entry ) ;
spin_unlock_irqrestore ( & mvi - > lock , flags ) ;
kfree ( mwq ) ;
}
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
static int mvs_handle_event ( struct mvs_info * mvi , void * data , int handler )
{
struct mvs_wq * mwq ;
int ret = 0 ;
mwq = kmalloc ( sizeof ( struct mvs_wq ) , GFP_ATOMIC ) ;
if ( mwq ) {
mwq - > mvi = mvi ;
mwq - > data = data ;
mwq - > handler = handler ;
MV_INIT_DELAYED_WORK ( & mwq - > work_q , mvs_work_queue , mwq ) ;
list_add_tail ( & mwq - > entry , & mvi - > wq_list ) ;
schedule_delayed_work ( & mwq - > work_q , HZ * 2 ) ;
} else
ret = - ENOMEM ;
return ret ;
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
static void mvs_sig_time_out ( unsigned long tphy )
{
struct mvs_phy * phy = ( struct mvs_phy * ) tphy ;
struct mvs_info * mvi = phy - > mvi ;
u8 phy_no ;
for ( phy_no = 0 ; phy_no < mvi - > chip - > n_phy ; phy_no + + ) {
if ( & mvi - > phy [ phy_no ] = = phy ) {
mv_dprintk ( " Get signature time out, reset phy %d \n " ,
phy_no + mvi - > id * mvi - > chip - > n_phy ) ;
2011-05-24 18:36:02 +04:00
MVS_CHIP_DISP - > phy_reset ( mvi , phy_no , MVS_HARD_RESET ) ;
2009-05-09 01:46:40 +04:00
}
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
void mvs_int_port ( struct mvs_info * mvi , int phy_no , u32 events )
{
u32 tmp ;
struct mvs_phy * phy = & mvi - > phy [ phy_no ] ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
phy - > irq_status = MVS_CHIP_DISP - > read_port_irq_stat ( mvi , phy_no ) ;
2011-05-24 18:37:25 +04:00
MVS_CHIP_DISP - > write_port_irq_stat ( mvi , phy_no , phy - > irq_status ) ;
mv_dprintk ( " phy %d ctrl sts=0x%08X. \n " , phy_no + mvi - > id * mvi - > chip - > n_phy ,
2009-05-09 01:46:40 +04:00
MVS_CHIP_DISP - > read_phy_ctl ( mvi , phy_no ) ) ;
2011-05-24 18:37:25 +04:00
mv_dprintk ( " phy %d irq sts = 0x%08X \n " , phy_no + mvi - > id * mvi - > chip - > n_phy ,
2009-05-09 01:46:40 +04:00
phy - > irq_status ) ;
2008-02-23 16:15:27 +03:00
2009-05-09 01:46:40 +04:00
/*
* events is port event now ,
* we need check the interrupt status which belongs to per port .
*/
2007-10-26 04:58:22 +04:00
2010-02-15 09:00:00 +03:00
if ( phy - > irq_status & PHYEV_DCDR_ERR ) {
2011-05-24 18:37:25 +04:00
mv_dprintk ( " phy %d STP decoding error. \n " ,
2010-02-15 09:00:00 +03:00
phy_no + mvi - > id * mvi - > chip - > n_phy ) ;
}
2009-05-09 01:46:40 +04:00
if ( phy - > irq_status & PHYEV_POOF ) {
2011-05-24 18:37:25 +04:00
mdelay ( 500 ) ;
2009-05-09 01:46:40 +04:00
if ( ! ( phy - > phy_event & PHY_PLUG_OUT ) ) {
int dev_sata = phy - > phy_type & PORT_TYPE_SATA ;
int ready ;
2010-02-15 09:00:00 +03:00
mvs_do_release_task ( mvi , phy_no , NULL ) ;
2009-05-09 01:46:40 +04:00
phy - > phy_event | = PHY_PLUG_OUT ;
2010-02-15 09:00:00 +03:00
MVS_CHIP_DISP - > clear_srs_irq ( mvi , 0 , 1 ) ;
2009-05-09 01:46:40 +04:00
mvs_handle_event ( mvi ,
( void * ) ( unsigned long ) phy_no ,
PHY_PLUG_EVENT ) ;
ready = mvs_is_phy_ready ( mvi , phy_no ) ;
if ( ready | | dev_sata ) {
if ( MVS_CHIP_DISP - > stp_reset )
MVS_CHIP_DISP - > stp_reset ( mvi ,
phy_no ) ;
else
MVS_CHIP_DISP - > phy_reset ( mvi ,
2011-05-24 18:36:02 +04:00
phy_no , MVS_SOFT_RESET ) ;
2009-05-09 01:46:40 +04:00
return ;
}
}
}
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
if ( phy - > irq_status & PHYEV_COMWAKE ) {
tmp = MVS_CHIP_DISP - > read_port_irq_mask ( mvi , phy_no ) ;
MVS_CHIP_DISP - > write_port_irq_mask ( mvi , phy_no ,
tmp | PHYEV_SIG_FIS ) ;
if ( phy - > timer . function = = NULL ) {
phy - > timer . data = ( unsigned long ) phy ;
phy - > timer . function = mvs_sig_time_out ;
2011-05-24 18:37:25 +04:00
phy - > timer . expires = jiffies + 5 * HZ ;
2009-05-09 01:46:40 +04:00
add_timer ( & phy - > timer ) ;
}
}
if ( phy - > irq_status & ( PHYEV_SIG_FIS | PHYEV_ID_DONE ) ) {
phy - > phy_status = mvs_is_phy_ready ( mvi , phy_no ) ;
mv_dprintk ( " notify plug in on phy[%d] \n " , phy_no ) ;
if ( phy - > phy_status ) {
mdelay ( 10 ) ;
MVS_CHIP_DISP - > detect_porttype ( mvi , phy_no ) ;
if ( phy - > phy_type & PORT_TYPE_SATA ) {
tmp = MVS_CHIP_DISP - > read_port_irq_mask (
mvi , phy_no ) ;
tmp & = ~ PHYEV_SIG_FIS ;
MVS_CHIP_DISP - > write_port_irq_mask ( mvi ,
phy_no , tmp ) ;
}
mvs_update_phyinfo ( mvi , phy_no , 0 ) ;
2010-02-15 09:00:00 +03:00
if ( phy - > phy_type & PORT_TYPE_SAS ) {
2011-05-24 18:36:02 +04:00
MVS_CHIP_DISP - > phy_reset ( mvi , phy_no , MVS_PHY_TUNE ) ;
2010-02-15 09:00:00 +03:00
mdelay ( 10 ) ;
}
2009-05-09 01:46:40 +04:00
mvs_bytes_dmaed ( mvi , phy_no ) ;
/* whether driver is going to handle hot plug */
if ( phy - > phy_event & PHY_PLUG_OUT ) {
2011-05-24 18:36:02 +04:00
mvs_port_notify_formed ( & phy - > sas_phy , 0 ) ;
2009-05-09 01:46:40 +04:00
phy - > phy_event & = ~ PHY_PLUG_OUT ;
}
} else {
mv_dprintk ( " plugin interrupt but phy%d is gone \n " ,
phy_no + mvi - > id * mvi - > chip - > n_phy ) ;
}
} else if ( phy - > irq_status & PHYEV_BROAD_CH ) {
2011-05-24 18:37:25 +04:00
mv_dprintk ( " phy %d broadcast change. \n " ,
2009-05-09 01:46:40 +04:00
phy_no + mvi - > id * mvi - > chip - > n_phy ) ;
2011-05-24 18:36:02 +04:00
mvs_handle_event ( mvi , ( void * ) ( unsigned long ) phy_no ,
EXP_BRCT_CHG ) ;
2009-05-09 01:46:40 +04:00
}
2007-10-26 04:58:22 +04:00
}
2009-05-09 01:46:40 +04:00
int mvs_int_rx ( struct mvs_info * mvi , bool self_clear )
2007-10-26 04:58:22 +04:00
{
2009-05-09 01:46:40 +04:00
u32 rx_prod_idx , rx_desc ;
bool attn = false ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
/* the first dword in the RX ring is special: it contains
* a mirror of the hardware ' s RX producer index , so that
* we don ' t have to stall the CPU reading that register .
* The actual RX ring is offset by one dword , due to this .
*/
rx_prod_idx = mvi - > rx_cons ;
mvi - > rx_cons = le32_to_cpu ( mvi - > rx [ 0 ] ) ;
if ( mvi - > rx_cons = = 0xfff ) /* h/w hasn't touched RX ring yet */
return 0 ;
2007-10-26 04:58:22 +04:00
2009-05-09 01:46:40 +04:00
/* The CMPL_Q may come late, read from register and try again
* note : if coalescing is enabled ,
* it will need to read from register every time for sure
*/
if ( unlikely ( mvi - > rx_cons = = rx_prod_idx ) )
mvi - > rx_cons = MVS_CHIP_DISP - > rx_update ( mvi ) & RX_RING_SZ_MASK ;
if ( mvi - > rx_cons = = rx_prod_idx )
return 0 ;
while ( mvi - > rx_cons ! = rx_prod_idx ) {
/* increment our internal RX consumer pointer */
rx_prod_idx = ( rx_prod_idx + 1 ) & ( MVS_RX_RING_SZ - 1 ) ;
rx_desc = le32_to_cpu ( mvi - > rx [ rx_prod_idx + 1 ] ) ;
if ( likely ( rx_desc & RXQ_DONE ) )
mvs_slot_complete ( mvi , rx_desc , 0 ) ;
if ( rx_desc & RXQ_ATTN ) {
attn = true ;
} else if ( rx_desc & RXQ_ERR ) {
if ( ! ( rx_desc & RXQ_DONE ) )
mvs_slot_complete ( mvi , rx_desc , 0 ) ;
} else if ( rx_desc & RXQ_SLOT_RESET ) {
mvs_slot_free ( mvi , rx_desc ) ;
}
}
if ( attn & & self_clear )
MVS_CHIP_DISP - > int_full ( mvi ) ;
return 0 ;
2007-10-26 04:58:22 +04:00
}
2015-12-27 22:21:19 +03:00
int mvs_gpio_write ( struct sas_ha_struct * sha , u8 reg_type , u8 reg_index ,
u8 reg_count , u8 * write_data )
{
struct mvs_prv_info * mvs_prv = sha - > lldd_ha ;
struct mvs_info * mvi = mvs_prv - > mvi [ 0 ] ;
if ( MVS_CHIP_DISP - > gpio_write ) {
return MVS_CHIP_DISP - > gpio_write ( mvs_prv , reg_type ,
reg_index , reg_count , write_data ) ;
}
return - ENOSYS ;
}