@ -1870,6 +1870,38 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
return rc ;
}
static int
_transport_map_smp_buffer ( struct device * dev , struct bsg_buffer * buf ,
dma_addr_t * dma_addr , size_t * dma_len , void * * p )
{
/* Check if the request is split across multiple segments */
if ( buf - > sg_cnt > 1 ) {
* p = dma_alloc_coherent ( dev , buf - > payload_len , dma_addr ,
GFP_KERNEL ) ;
if ( ! * p )
return - ENOMEM ;
* dma_len = buf - > payload_len ;
} else {
if ( ! dma_map_sg ( dev , buf - > sg_list , 1 , DMA_BIDIRECTIONAL ) )
return - ENOMEM ;
* dma_addr = sg_dma_address ( buf - > sg_list ) ;
* dma_len = sg_dma_len ( buf - > sg_list ) ;
* p = NULL ;
}
return 0 ;
}
static void
_transport_unmap_smp_buffer ( struct device * dev , struct bsg_buffer * buf ,
dma_addr_t dma_addr , void * p )
{
if ( p )
dma_free_coherent ( dev , buf - > payload_len , p , dma_addr ) ;
else
dma_unmap_sg ( dev , buf - > sg_list , 1 , DMA_BIDIRECTIONAL ) ;
}
/**
* _transport_smp_handler - transport portal for smp passthru
* @ shost : shost object
@ -1880,9 +1912,9 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
* Example :
* smp_rep_general / sys / class / bsg / expander - 5 : 0
*/
static int
_transport_smp_handler ( struct Scsi_Host * shost , struct sas_rphy * rphy ,
struct request * req )
static void
_transport_smp_handler ( struct bsg_job * job , struct Scsi_Host * shost ,
struct sas_rphy * rphy )
{
struct MPT3SAS_ADAPTER * ioc = shost_priv ( shost ) ;
Mpi2SmpPassthroughRequest_t * mpi_request ;
@ -1891,33 +1923,25 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
u16 smid ;
u32 ioc_state ;
void * psge ;
u8 issue_reset = 0 ;
dma_addr_t dma_addr_in = 0 ;
dma_addr_t dma_addr_out = 0 ;
dma_addr_t pci_dma_in = 0 ;
dma_addr_t pci_dma_out = 0 ;
void * pci_addr_in = NULL ;
void * pci_addr_out = NULL ;
dma_addr_t dma_addr_in ;
dma_addr_t dma_addr_out ;
void * addr_in = NULL ;
void * addr_out = NULL ;
size_t dma_len_in ;
size_t dma_len_out ;
u16 wait_state_count ;
struct request * rsp = req - > next_rq ;
struct bio_vec bvec ;
struct bvec_iter iter ;
if ( ! rsp ) {
pr_err ( MPT3SAS_FMT " %s: the smp response space is missing \n " ,
ioc - > name , __func__ ) ;
return - EINVAL ;
}
unsigned int reslen = 0 ;
if ( ioc - > shost_recovery | | ioc - > pci_error_recovery ) {
pr_info ( MPT3SAS_FMT " %s: host reset in progress! \n " ,
__func__ , ioc - > name ) ;
return - EFAULT ;
rc = - EFAULT ;
goto out ;
}
rc = mutex_lock_interruptible ( & ioc - > transport_cmds . mutex ) ;
if ( rc )
return rc ;
goto out ;
if ( ioc - > transport_cmds . status ! = MPT3_CMD_NOT_USED ) {
pr_err ( MPT3SAS_FMT " %s: transport_cmds in use \n " , ioc - > name ,
@ -1927,58 +1951,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
}
ioc - > transport_cmds . status = MPT3_CMD_PENDING ;
/* Check if the request is split across multiple segments */
if ( bio_multiple_segments ( req - > bio ) ) {
u32 offset = 0 ;
/* Allocate memory and copy the request */
pci_addr_out = pci_alloc_consistent ( ioc - > pdev ,
blk_rq_bytes ( req ) , & pci_dma_out ) ;
if ( ! pci_addr_out ) {
pr_info ( MPT3SAS_FMT " %s(): PCI Addr out = NULL \n " ,
ioc - > name , __func__ ) ;
rc = - ENOMEM ;
goto out ;
}
bio_for_each_segment ( bvec , req - > bio , iter ) {
memcpy ( pci_addr_out + offset ,
page_address ( bvec . bv_page ) + bvec . bv_offset ,
bvec . bv_len ) ;
offset + = bvec . bv_len ;
}
} else {
dma_addr_out = pci_map_single ( ioc - > pdev , bio_data ( req - > bio ) ,
blk_rq_bytes ( req ) , PCI_DMA_BIDIRECTIONAL ) ;
if ( pci_dma_mapping_error ( ioc - > pdev , dma_addr_out ) ) {
pr_info ( MPT3SAS_FMT " %s(): DMA Addr out = NULL \n " ,
ioc - > name , __func__ ) ;
rc = - ENOMEM ;
goto free_pci ;
}
rc = _transport_map_smp_buffer ( & ioc - > pdev - > dev , & job - > request_payload ,
& dma_addr_out , & dma_len_out , & addr_out ) ;
if ( rc )
goto out ;
if ( addr_out ) {
sg_copy_to_buffer ( job - > request_payload . sg_list ,
job - > request_payload . sg_cnt , addr_out ,
job - > request_payload . payload_len ) ;
}
/* Check if the response needs to be populated across
* multiple segments */
if ( bio_multiple_segments ( rsp - > bio ) ) {
pci_addr_in = pci_alloc_consistent ( ioc - > pdev , blk_rq_bytes ( rsp ) ,
& pci_dma_in ) ;
if ( ! pci_addr_in ) {
pr_info ( MPT3SAS_FMT " %s(): PCI Addr in = NULL \n " ,
ioc - > name , __func__ ) ;
rc = - ENOMEM ;
goto unmap ;
}
} else {
dma_addr_in = pci_map_single ( ioc - > pdev , bio_data ( rsp - > bio ) ,
blk_rq_bytes ( rsp ) , PCI_DMA_BIDIRECTIONAL ) ;
if ( pci_dma_mapping_error ( ioc - > pdev , dma_addr_in ) ) {
pr_info ( MPT3SAS_FMT " %s(): DMA Addr in = NULL \n " ,
ioc - > name , __func__ ) ;
rc = - ENOMEM ;
goto unmap ;
}
}
rc = _transport_map_smp_buffer ( & ioc - > pdev - > dev , & job - > reply_payload ,
& dma_addr_in , & dma_len_in , & addr_in ) ;
if ( rc )
goto unmap_out ;
wait_state_count = 0 ;
ioc_state = mpt3sas_base_get_iocstate ( ioc , 1 ) ;
@ -1988,7 +1974,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
" %s: failed due to ioc not operational \n " ,
ioc - > name , __func__ ) ;
rc = - EFAULT ;
goto unmap ;
goto unmap_in ;
}
ssleep ( 1 ) ;
ioc_state = mpt3sas_base_get_iocstate ( ioc , 1 ) ;
@ -2005,7 +1991,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
pr_err ( MPT3SAS_FMT " %s: failed obtaining a smid \n " ,
ioc - > name , __func__ ) ;
rc = - EAGAIN ;
goto unmap ;
goto unmap_in ;
}
rc = 0 ;
@ -2018,15 +2004,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
mpi_request - > SASAddress = ( rphy ) ?
cpu_to_le64 ( rphy - > identify . sas_address ) :
cpu_to_le64 ( ioc - > sas_hba . sas_address ) ;
mpi_request - > RequestDataLength = cpu_to_le16 ( blk_rq_bytes ( req ) - 4 ) ;
mpi_request - > RequestDataLength = cpu_to_le16 ( dma_len_out - 4 ) ;
psge = & mpi_request - > SGL ;
if ( bio_multiple_segments ( req - > bio ) )
ioc - > build_sg ( ioc , psge , pci_dma_out , ( blk_rq_bytes ( req ) - 4 ) ,
pci_dma_in , ( blk_rq_bytes ( rsp ) + 4 ) ) ;
else
ioc - > build_sg ( ioc , psge , dma_addr_out , ( blk_rq_bytes ( req ) - 4 ) ,
dma_addr_in , ( blk_rq_bytes ( rsp ) + 4 ) ) ;
ioc - > build_sg ( ioc , psge , dma_addr_out , dma_len_out - 4 , dma_addr_in ,
dma_len_in - 4 ) ;
dtransportprintk ( ioc , pr_info ( MPT3SAS_FMT
" %s - sending smp request \n " , ioc - > name , __func__ ) ) ;
@ -2040,83 +2022,51 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
__func__ , ioc - > name ) ;
_debug_dump_mf ( mpi_request ,
sizeof ( Mpi2SmpPassthroughRequest_t ) / 4 ) ;
if ( ! ( ioc - > transport_cmds . status & MPT3_CMD_RESET ) )
issue_reset = 1 ;
goto issue_host_reset ;
if ( ! ( ioc - > transport_cmds . status & MPT3_CMD_RESET ) ) {
mpt3sas_base_hard_reset_handler ( ioc , FORCE_BIG_HAMMER ) ;
rc = - ETIMEDOUT ;
goto unmap_in ;
}
}
dtransportprintk ( ioc , pr_info ( MPT3SAS_FMT
" %s - complete \n " , ioc - > name , __func__ ) ) ;
if ( ioc - > transport_cmds . status & MPT3_CMD_REPLY_VALID ) {
mpi_reply = ioc - > transport_cmds . reply ;
dtransportprintk ( ioc , pr_info ( MPT3SAS_FMT
" %s - reply data transfer size(%d) \n " ,
ioc - > name , __func__ ,
le16_to_cpu ( mpi_reply - > ResponseDataLength ) ) ) ;
memcpy ( scsi_req ( req ) - > sense , mpi_reply , sizeof ( * mpi_reply ) ) ;
scsi_req ( req ) - > sense_len = sizeof ( * mpi_reply ) ;
scsi_req ( req ) - > resid_len = 0 ;
scsi_req ( rsp ) - > resid_len - =
le16_to_cpu ( mpi_reply - > ResponseDataLength ) ;
/* check if the resp needs to be copied from the allocated
* pci mem */
if ( bio_multiple_segments ( rsp - > bio ) ) {
u32 offset = 0 ;
u32 bytes_to_copy =
le16_to_cpu ( mpi_reply - > ResponseDataLength ) ;
bio_for_each_segment ( bvec , rsp - > bio , iter ) {
if ( bytes_to_copy < = bvec . bv_len ) {
memcpy ( page_address ( bvec . bv_page ) +
bvec . bv_offset , pci_addr_in +
offset , bytes_to_copy ) ;
break ;
} else {
memcpy ( page_address ( bvec . bv_page ) +
bvec . bv_offset , pci_addr_in +
offset , bvec . bv_len ) ;
bytes_to_copy - = bvec . bv_len ;
}
offset + = bvec . bv_len ;
}
}
} else {
if ( ! ( ioc - > transport_cmds . status & MPT3_CMD_REPLY_VALID ) ) {
dtransportprintk ( ioc , pr_info ( MPT3SAS_FMT
" %s - no reply \n " , ioc - > name , __func__ ) ) ;
rc = - ENXIO ;
goto unmap_in ;
}
issue_host_reset :
if ( issue_reset ) {
mpt3sas_base_hard_reset_handler ( ioc , FORCE_BIG_HAMMER ) ;
rc = - ETIMEDOUT ;
}
mpi_reply = ioc - > transport_cmds . reply ;
unmap :
if ( dma_addr_out )
pci_unmap_single ( ioc - > pdev , dma_addr_out , blk_rq_bytes ( req ) ,
PCI_DMA_BIDIRECTIONAL ) ;
if ( dma_addr_in )
pci_unmap_single ( ioc - > pdev , dma_addr_in , blk_rq_bytes ( rsp ) ,
PCI_DMA_BIDIRECTIONAL ) ;
dtransportprintk ( ioc ,
pr_info ( MPT3SAS_FMT " %s - reply data transfer size(%d) \n " ,
ioc - > name , __func__ ,
le16_to_cpu ( mpi_reply - > ResponseDataLength ) ) ) ;
free_pci :
if ( pci_addr_out )
pci_free_consistent ( ioc - > pdev , blk_rq_bytes ( req ) , pci_addr_out ,
pci_dma_out ) ;
memcpy ( job - > reply , mpi_reply , sizeof ( * mpi_reply ) ) ;
job - > reply_len = sizeof ( * mpi_reply ) ;
reslen = le16_to_cpu ( mpi_reply - > ResponseDataLength ) ;
if ( pci_addr_in )
pci_free_consistent ( ioc - > pdev , blk_rq_bytes ( rsp ) , pci_addr_in ,
pci_dma_in ) ;
if ( addr_in ) {
sg_copy_to_buffer ( job - > reply_payload . sg_list ,
job - > reply_payload . sg_cnt , addr_in ,
job - > reply_payload . payload_len ) ;
}
rc = 0 ;
unmap_in :
_transport_unmap_smp_buffer ( & ioc - > pdev - > dev , & job - > reply_payload ,
dma_addr_in , addr_in ) ;
unmap_out :
_transport_unmap_smp_buffer ( & ioc - > pdev - > dev , & job - > request_payload ,
dma_addr_out , addr_out ) ;
out :
ioc - > transport_cmds . status = MPT3_CMD_NOT_USED ;
mutex_unlock ( & ioc - > transport_cmds . mutex ) ;
return rc ;
bsg_job_done ( job , rc , reslen ) ;
}
struct sas_function_template mpt3sas_transport_functions = {