@ -12,6 +12,15 @@
# include "hisi_sas.h"
# define DRV_NAME "hisi_sas"
# define DEV_IS_GONE(dev) \
( ( ! dev ) | | ( dev - > dev_type = = SAS_PHY_UNUSED ) )
static struct hisi_hba * dev_to_hisi_hba ( struct domain_device * device )
{
return device - > port - > ha - > lldd_ha ;
}
static void hisi_sas_slot_index_clear ( struct hisi_hba * hisi_hba , int slot_idx )
{
void * bitmap = hisi_hba - > slot_index_tags ;
@ -19,6 +28,31 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
clear_bit ( slot_idx , bitmap ) ;
}
static void hisi_sas_slot_index_free ( struct hisi_hba * hisi_hba , int slot_idx )
{
hisi_sas_slot_index_clear ( hisi_hba , slot_idx ) ;
}
static void hisi_sas_slot_index_set ( struct hisi_hba * hisi_hba , int slot_idx )
{
void * bitmap = hisi_hba - > slot_index_tags ;
set_bit ( slot_idx , bitmap ) ;
}
static int hisi_sas_slot_index_alloc ( struct hisi_hba * hisi_hba , int * slot_idx )
{
unsigned int index ;
void * bitmap = hisi_hba - > slot_index_tags ;
index = find_first_zero_bit ( bitmap , hisi_hba - > slot_index_count ) ;
if ( index > = hisi_hba - > slot_index_count )
return - SAS_QUEUE_FULL ;
hisi_sas_slot_index_set ( hisi_hba , index ) ;
* slot_idx = index ;
return 0 ;
}
static void hisi_sas_slot_index_init ( struct hisi_hba * hisi_hba )
{
int i ;
@ -26,6 +60,199 @@ static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
for ( i = 0 ; i < hisi_hba - > slot_index_count ; + + i )
hisi_sas_slot_index_clear ( hisi_hba , i ) ;
}
static int hisi_sas_task_prep_ssp ( struct hisi_hba * hisi_hba ,
struct hisi_sas_slot * slot , int is_tmf ,
struct hisi_sas_tmf_task * tmf )
{
return hisi_hba - > hw - > prep_ssp ( hisi_hba , slot , is_tmf , tmf ) ;
}
static int hisi_sas_task_prep ( struct sas_task * task , struct hisi_hba * hisi_hba ,
int is_tmf , struct hisi_sas_tmf_task * tmf ,
int * pass )
{
struct domain_device * device = task - > dev ;
struct hisi_sas_device * sas_dev = device - > lldd_dev ;
struct hisi_sas_port * port ;
struct hisi_sas_slot * slot ;
struct hisi_sas_cmd_hdr * cmd_hdr_base ;
struct device * dev = & hisi_hba - > pdev - > dev ;
int dlvry_queue_slot , dlvry_queue , n_elem = 0 , rc , slot_idx ;
if ( ! device - > port ) {
struct task_status_struct * ts = & task - > task_status ;
ts - > resp = SAS_TASK_UNDELIVERED ;
ts - > stat = SAS_PHY_DOWN ;
/*
* libsas will use dev - > port , should
* not call task_done for sata
*/
if ( device - > dev_type ! = SAS_SATA_DEV )
task - > task_done ( task ) ;
return 0 ;
}
if ( DEV_IS_GONE ( sas_dev ) ) {
if ( sas_dev )
dev_info ( dev , " task prep: device %llu not ready \n " ,
sas_dev - > device_id ) ;
else
dev_info ( dev , " task prep: device %016llx not ready \n " ,
SAS_ADDR ( device - > sas_addr ) ) ;
rc = SAS_PHY_DOWN ;
return rc ;
}
port = device - > port - > lldd_port ;
if ( port & & ! port - > port_attached & & ! tmf ) {
if ( sas_protocol_ata ( task - > task_proto ) ) {
struct task_status_struct * ts = & task - > task_status ;
dev_info ( dev ,
" task prep: SATA/STP port%d not attach device \n " ,
device - > port - > id ) ;
ts - > resp = SAS_TASK_COMPLETE ;
ts - > stat = SAS_PHY_DOWN ;
task - > task_done ( task ) ;
} else {
struct task_status_struct * ts = & task - > task_status ;
dev_info ( dev ,
" task prep: SAS port%d does not attach device \n " ,
device - > port - > id ) ;
ts - > resp = SAS_TASK_UNDELIVERED ;
ts - > stat = SAS_PHY_DOWN ;
task - > task_done ( task ) ;
}
return 0 ;
}
if ( ! sas_protocol_ata ( task - > task_proto ) ) {
if ( task - > num_scatter ) {
n_elem = dma_map_sg ( dev , task - > scatter ,
task - > num_scatter , task - > data_dir ) ;
if ( ! n_elem ) {
rc = - ENOMEM ;
goto prep_out ;
}
}
} else
n_elem = task - > num_scatter ;
rc = hisi_sas_slot_index_alloc ( hisi_hba , & slot_idx ) ;
if ( rc )
goto err_out ;
rc = hisi_hba - > hw - > get_free_slot ( hisi_hba , & dlvry_queue ,
& dlvry_queue_slot ) ;
if ( rc )
goto err_out_tag ;
slot = & hisi_hba - > slot_info [ slot_idx ] ;
memset ( slot , 0 , sizeof ( struct hisi_sas_slot ) ) ;
slot - > idx = slot_idx ;
slot - > n_elem = n_elem ;
slot - > dlvry_queue = dlvry_queue ;
slot - > dlvry_queue_slot = dlvry_queue_slot ;
cmd_hdr_base = hisi_hba - > cmd_hdr [ dlvry_queue ] ;
slot - > cmd_hdr = & cmd_hdr_base [ dlvry_queue_slot ] ;
slot - > task = task ;
slot - > port = port ;
task - > lldd_task = slot ;
slot - > status_buffer = dma_pool_alloc ( hisi_hba - > status_buffer_pool ,
GFP_ATOMIC ,
& slot - > status_buffer_dma ) ;
if ( ! slot - > status_buffer )
goto err_out_slot_buf ;
memset ( slot - > status_buffer , 0 , HISI_SAS_STATUS_BUF_SZ ) ;
slot - > command_table = dma_pool_alloc ( hisi_hba - > command_table_pool ,
GFP_ATOMIC ,
& slot - > command_table_dma ) ;
if ( ! slot - > command_table )
goto err_out_status_buf ;
memset ( slot - > command_table , 0 , HISI_SAS_COMMAND_TABLE_SZ ) ;
memset ( slot - > cmd_hdr , 0 , sizeof ( struct hisi_sas_cmd_hdr ) ) ;
switch ( task - > task_proto ) {
case SAS_PROTOCOL_SSP :
rc = hisi_sas_task_prep_ssp ( hisi_hba , slot , is_tmf , tmf ) ;
break ;
case SAS_PROTOCOL_SATA :
case SAS_PROTOCOL_STP :
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP :
default :
dev_err ( dev , " task prep: unknown/unsupported proto (0x%x) \n " ,
task - > task_proto ) ;
rc = - EINVAL ;
break ;
}
if ( rc ) {
dev_err ( dev , " task prep: rc = 0x%x \n " , rc ) ;
if ( slot - > sge_page )
goto err_out_sge ;
goto err_out_command_table ;
}
list_add_tail ( & slot - > entry , & port - > list ) ;
spin_lock ( & task - > task_state_lock ) ;
task - > task_state_flags | = SAS_TASK_AT_INITIATOR ;
spin_unlock ( & task - > task_state_lock ) ;
hisi_hba - > slot_prep = slot ;
sas_dev - > running_req + + ;
+ + ( * pass ) ;
return rc ;
err_out_sge :
dma_pool_free ( hisi_hba - > sge_page_pool , slot - > sge_page ,
slot - > sge_page_dma ) ;
err_out_command_table :
dma_pool_free ( hisi_hba - > command_table_pool , slot - > command_table ,
slot - > command_table_dma ) ;
err_out_status_buf :
dma_pool_free ( hisi_hba - > status_buffer_pool , slot - > status_buffer ,
slot - > status_buffer_dma ) ;
err_out_slot_buf :
/* Nothing to be done */
err_out_tag :
hisi_sas_slot_index_free ( hisi_hba , slot_idx ) ;
err_out :
dev_err ( dev , " task prep: failed[%d]! \n " , rc ) ;
if ( ! sas_protocol_ata ( task - > task_proto ) )
if ( n_elem )
dma_unmap_sg ( dev , task - > scatter , n_elem ,
task - > data_dir ) ;
prep_out :
return rc ;
}
static int hisi_sas_task_exec ( struct sas_task * task , gfp_t gfp_flags ,
int is_tmf , struct hisi_sas_tmf_task * tmf )
{
u32 rc ;
u32 pass = 0 ;
unsigned long flags ;
struct hisi_hba * hisi_hba = dev_to_hisi_hba ( task - > dev ) ;
struct device * dev = & hisi_hba - > pdev - > dev ;
/* protect task_prep and start_delivery sequence */
spin_lock_irqsave ( & hisi_hba - > lock , flags ) ;
rc = hisi_sas_task_prep ( task , hisi_hba , is_tmf , tmf , & pass ) ;
if ( rc )
dev_err ( dev , " task exec: failed[%d]! \n " , rc ) ;
if ( likely ( pass ) )
hisi_hba - > hw - > start_delivery ( hisi_hba ) ;
spin_unlock_irqrestore ( & hisi_hba - > lock , flags ) ;
return rc ;
}
static void hisi_sas_bytes_dmaed ( struct hisi_hba * hisi_hba , int phy_no )
{
@ -100,6 +327,12 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
INIT_WORK ( & phy - > phyup_ws , hisi_sas_phyup_work ) ;
}
static int hisi_sas_queue_command ( struct sas_task * task , gfp_t gfp_flags )
{
return hisi_sas_task_exec ( task , gfp_flags , 0 , NULL ) ;
}
static struct scsi_transport_template * hisi_sas_stt ;
static struct scsi_host_template hisi_sas_sht = {
@ -122,6 +355,7 @@ static struct scsi_host_template hisi_sas_sht = {
} ;
static struct sas_domain_function_template hisi_sas_transport_ops = {
. lldd_execute_task = hisi_sas_queue_command ,
} ;
static int hisi_sas_alloc ( struct hisi_hba * hisi_hba , struct Scsi_Host * shost )