2007-07-06 00:16:51 +04:00
/*
2008-04-04 00:13:13 +04:00
* QLogic Fibre Channel HBA Driver
* Copyright ( c ) 2003 - 2008 QLogic Corporation
2007-07-06 00:16:51 +04:00
*
2008-04-04 00:13:13 +04:00
* See LICENSE . qla2xxx for copyright and licensing details .
2007-07-06 00:16:51 +04:00
*/
# include "qla_def.h"
2008-11-06 21:40:19 +03:00
# include "qla_gbl.h"
2007-07-06 00:16:51 +04:00
# include <linux/moduleparam.h>
# include <linux/vmalloc.h>
# include <linux/smp_lock.h>
# include <linux/list.h>
# include <scsi/scsi_tcq.h>
# include <scsi/scsicam.h>
# include <linux/delay.h>
void
qla2x00_vp_stop_timer ( scsi_qla_host_t * vha )
{
2008-11-06 21:40:19 +03:00
if ( vha - > vp_idx & & vha - > timer_active ) {
2007-07-06 00:16:51 +04:00
del_timer_sync ( & vha - > timer ) ;
vha - > timer_active = 0 ;
}
}
2008-01-17 20:02:15 +03:00
static uint32_t
2007-07-06 00:16:51 +04:00
qla24xx_allocate_vp_id ( scsi_qla_host_t * vha )
{
uint32_t vp_id ;
2008-11-06 21:40:19 +03:00
struct qla_hw_data * ha = vha - > hw ;
2007-07-06 00:16:51 +04:00
/* Find an empty slot and assign an vp_id */
2008-05-13 09:21:11 +04:00
mutex_lock ( & ha - > vport_lock ) ;
2007-11-12 21:30:58 +03:00
vp_id = find_first_zero_bit ( ha - > vp_idx_map , ha - > max_npiv_vports + 1 ) ;
if ( vp_id > ha - > max_npiv_vports ) {
DEBUG15 ( printk ( " vp_id %d is bigger than max-supported %d. \n " ,
vp_id , ha - > max_npiv_vports ) ) ;
2008-05-13 09:21:11 +04:00
mutex_unlock ( & ha - > vport_lock ) ;
2007-07-06 00:16:51 +04:00
return vp_id ;
}
2007-11-12 21:30:58 +03:00
set_bit ( vp_id , ha - > vp_idx_map ) ;
2007-07-06 00:16:51 +04:00
ha - > num_vhosts + + ;
2008-07-11 03:55:51 +04:00
ha - > cur_vport_count + + ;
2007-07-06 00:16:51 +04:00
vha - > vp_idx = vp_id ;
2008-11-06 21:40:19 +03:00
list_add_tail ( & vha - > list , & ha - > vp_list ) ;
2008-05-13 09:21:11 +04:00
mutex_unlock ( & ha - > vport_lock ) ;
2007-07-06 00:16:51 +04:00
return vp_id ;
}
void
qla24xx_deallocate_vp_id ( scsi_qla_host_t * vha )
{
uint16_t vp_id ;
2008-11-06 21:40:19 +03:00
struct qla_hw_data * ha = vha - > hw ;
2007-07-06 00:16:51 +04:00
2008-05-13 09:21:11 +04:00
mutex_lock ( & ha - > vport_lock ) ;
2007-07-06 00:16:51 +04:00
vp_id = vha - > vp_idx ;
ha - > num_vhosts - - ;
2008-07-11 03:55:51 +04:00
ha - > cur_vport_count - - ;
2007-11-12 21:30:58 +03:00
clear_bit ( vp_id , ha - > vp_idx_map ) ;
2008-11-06 21:40:19 +03:00
list_del ( & vha - > list ) ;
2008-05-13 09:21:11 +04:00
mutex_unlock ( & ha - > vport_lock ) ;
2007-07-06 00:16:51 +04:00
}
2008-01-17 20:02:15 +03:00
static scsi_qla_host_t *
2008-11-06 21:40:19 +03:00
qla24xx_find_vhost_by_name ( struct qla_hw_data * ha , uint8_t * port_name )
2007-07-06 00:16:51 +04:00
{
scsi_qla_host_t * vha ;
2009-03-05 22:07:02 +03:00
struct scsi_qla_host * tvha ;
2007-07-06 00:16:51 +04:00
/* Locate matching device in database. */
2009-03-05 22:07:02 +03:00
list_for_each_entry_safe ( vha , tvha , & ha - > vp_list , list ) {
2007-07-06 00:16:51 +04:00
if ( ! memcmp ( port_name , vha - > port_name , WWN_SIZE ) )
return vha ;
}
return NULL ;
}
/*
* qla2x00_mark_vp_devices_dead
* Updates fcport state when device goes offline .
*
* Input :
* ha = adapter block pointer .
* fcport = port structure pointer .
*
* Return :
* None .
*
* Context :
*/
2007-09-21 01:07:47 +04:00
static void
2007-07-06 00:16:51 +04:00
qla2x00_mark_vp_devices_dead ( scsi_qla_host_t * vha )
{
fc_port_t * fcport ;
2008-11-06 21:40:19 +03:00
list_for_each_entry ( fcport , & vha - > vp_fcports , list ) {
2007-07-06 00:16:51 +04:00
DEBUG15 ( printk ( " scsi(%ld): Marking port dead, "
" loop_id=0x%04x :%x \n " ,
vha - > host_no , fcport - > loop_id , fcport - > vp_idx ) ) ;
2008-12-10 03:45:39 +03:00
atomic_set ( & fcport - > state , FCS_DEVICE_DEAD ) ;
2007-07-06 00:16:51 +04:00
qla2x00_mark_device_lost ( vha , fcport , 0 , 0 ) ;
2008-07-24 19:31:49 +04:00
atomic_set ( & fcport - > state , FCS_UNCONFIGURED ) ;
2007-07-06 00:16:51 +04:00
}
}
int
qla24xx_disable_vp ( scsi_qla_host_t * vha )
{
int ret ;
ret = qla24xx_control_vp ( vha , VCE_COMMAND_DISABLE_VPS_LOGO_ALL ) ;
atomic_set ( & vha - > loop_state , LOOP_DOWN ) ;
atomic_set ( & vha - > loop_down_timer , LOOP_DOWN_TIME ) ;
qla2x00_mark_vp_devices_dead ( vha ) ;
atomic_set ( & vha - > vp_state , VP_FAILED ) ;
vha - > flags . management_server_logged_in = 0 ;
if ( ret = = QLA_SUCCESS ) {
fc_vport_set_state ( vha - > fc_vport , FC_VPORT_DISABLED ) ;
} else {
fc_vport_set_state ( vha - > fc_vport , FC_VPORT_FAILED ) ;
return - 1 ;
}
return 0 ;
}
int
qla24xx_enable_vp ( scsi_qla_host_t * vha )
{
int ret ;
2008-11-06 21:40:19 +03:00
struct qla_hw_data * ha = vha - > hw ;
scsi_qla_host_t * base_vha = pci_get_drvdata ( ha - > pdev ) ;
2007-07-06 00:16:51 +04:00
/* Check if physical ha port is Up */
2008-11-06 21:40:19 +03:00
if ( atomic_read ( & base_vha - > loop_state ) = = LOOP_DOWN | |
atomic_read ( & base_vha - > loop_state ) = = LOOP_DEAD ) {
2007-07-06 00:16:51 +04:00
vha - > vp_err_state = VP_ERR_PORTDWN ;
fc_vport_set_state ( vha - > fc_vport , FC_VPORT_LINKDOWN ) ;
goto enable_failed ;
}
/* Initialize the new vport unless it is a persistent port */
2008-05-13 09:21:11 +04:00
mutex_lock ( & ha - > vport_lock ) ;
2007-07-06 00:16:51 +04:00
ret = qla24xx_modify_vp_config ( vha ) ;
2008-05-13 09:21:11 +04:00
mutex_unlock ( & ha - > vport_lock ) ;
2007-07-06 00:16:51 +04:00
if ( ret ! = QLA_SUCCESS ) {
fc_vport_set_state ( vha - > fc_vport , FC_VPORT_FAILED ) ;
goto enable_failed ;
}
DEBUG15 ( qla_printk ( KERN_INFO , ha ,
" Virtual port with id: %d - Enabled \n " , vha - > vp_idx ) ) ;
return 0 ;
enable_failed :
DEBUG15 ( qla_printk ( KERN_INFO , ha ,
" Virtual port with id: %d - Disabled \n " , vha - > vp_idx ) ) ;
return 1 ;
}
2007-09-21 01:07:47 +04:00
static void
2007-07-06 00:16:51 +04:00
qla24xx_configure_vp ( scsi_qla_host_t * vha )
{
struct fc_vport * fc_vport ;
int ret ;
fc_vport = vha - > fc_vport ;
DEBUG15 ( printk ( " scsi(%ld): %s: change request #3 for this host. \n " ,
vha - > host_no , __func__ ) ) ;
ret = qla2x00_send_change_request ( vha , 0x3 , vha - > vp_idx ) ;
if ( ret ! = QLA_SUCCESS ) {
2008-11-06 21:40:19 +03:00
DEBUG15 ( qla_printk ( KERN_ERR , vha - > hw , " Failed to enable "
" receiving of RSCN requests: 0x%x \n " , ret ) ) ;
2007-07-06 00:16:51 +04:00
return ;
} else {
/* Corresponds to SCR enabled */
clear_bit ( VP_SCR_NEEDED , & vha - > vp_flags ) ;
}
vha - > flags . online = 1 ;
if ( qla24xx_configure_vhba ( vha ) )
return ;
atomic_set ( & vha - > vp_state , VP_ACTIVE ) ;
fc_vport_set_state ( fc_vport , FC_VPORT_ACTIVE ) ;
}
void
2008-12-10 03:45:39 +03:00
qla2x00_alert_all_vps ( struct rsp_que * rsp , uint16_t * mb )
2007-07-06 00:16:51 +04:00
{
2009-03-05 22:07:02 +03:00
scsi_qla_host_t * vha , * tvha ;
2008-12-10 03:45:39 +03:00
struct qla_hw_data * ha = rsp - > hw ;
2008-11-06 21:40:19 +03:00
int i = 0 ;
2007-07-06 00:16:51 +04:00
2009-03-05 22:07:02 +03:00
list_for_each_entry_safe ( vha , tvha , & ha - > vp_list , list ) {
2008-11-06 21:40:19 +03:00
if ( vha - > vp_idx ) {
2007-07-06 00:16:51 +04:00
switch ( mb [ 0 ] ) {
case MBA_LIP_OCCURRED :
case MBA_LOOP_UP :
case MBA_LOOP_DOWN :
case MBA_LIP_RESET :
case MBA_POINT_TO_POINT :
case MBA_CHG_IN_CONNECTION :
case MBA_PORT_UPDATE :
case MBA_RSCN_UPDATE :
DEBUG15 ( printk ( " scsi(%ld)%s: Async_event for "
2008-11-06 21:40:19 +03:00
" VP[%d], mb = 0x%x, vha=%p \n " ,
vha - > host_no , __func__ , i , * mb , vha ) ) ;
2008-12-10 03:45:39 +03:00
qla2x00_async_event ( vha , rsp , mb ) ;
2007-07-06 00:16:51 +04:00
break ;
}
}
2008-11-06 21:40:19 +03:00
i + + ;
2007-07-06 00:16:51 +04:00
}
}
2008-11-06 21:40:19 +03:00
int
2007-07-06 00:16:51 +04:00
qla2x00_vp_abort_isp ( scsi_qla_host_t * vha )
{
/*
* Physical port will do most of the abort and recovery work . We can
* just treat it as a loop down
*/
if ( atomic_read ( & vha - > loop_state ) ! = LOOP_DOWN ) {
atomic_set ( & vha - > loop_state , LOOP_DOWN ) ;
qla2x00_mark_all_devices_lost ( vha , 0 ) ;
} else {
if ( ! atomic_read ( & vha - > loop_down_timer ) )
atomic_set ( & vha - > loop_down_timer , LOOP_DOWN_TIME ) ;
}
2008-11-06 21:40:19 +03:00
/* To exclusively reset vport, we need to log it out first.*/
if ( ! test_bit ( ABORT_ISP_ACTIVE , & vha - > dpc_flags ) )
qla24xx_control_vp ( vha , VCE_COMMAND_DISABLE_VPS_LOGO_ALL ) ;
2007-07-06 00:16:51 +04:00
DEBUG15 ( printk ( " scsi(%ld): Scheduling enable of Vport %d... \n " ,
vha - > host_no , vha - > vp_idx ) ) ;
2008-11-06 21:40:19 +03:00
return qla24xx_enable_vp ( vha ) ;
2007-07-06 00:16:51 +04:00
}
2008-01-17 20:02:15 +03:00
static int
2007-07-06 00:16:51 +04:00
qla2x00_do_dpc_vp ( scsi_qla_host_t * vha )
{
2008-11-06 21:40:19 +03:00
struct qla_hw_data * ha = vha - > hw ;
scsi_qla_host_t * base_vha = pci_get_drvdata ( ha - > pdev ) ;
2008-04-04 00:13:31 +04:00
2007-07-06 00:16:51 +04:00
if ( test_and_clear_bit ( VP_IDX_ACQUIRED , & vha - > vp_flags ) ) {
/* VP acquired. complete port configuration */
2008-11-06 21:40:19 +03:00
if ( atomic_read ( & base_vha - > loop_state ) = = LOOP_READY ) {
2008-04-04 00:13:31 +04:00
qla24xx_configure_vp ( vha ) ;
} else {
set_bit ( VP_IDX_ACQUIRED , & vha - > vp_flags ) ;
2008-11-06 21:40:19 +03:00
set_bit ( VP_DPC_NEEDED , & base_vha - > dpc_flags ) ;
2008-04-04 00:13:31 +04:00
}
2007-07-06 00:16:51 +04:00
return 0 ;
}
2008-11-06 21:40:19 +03:00
if ( test_bit ( FCPORT_UPDATE_NEEDED , & vha - > dpc_flags ) ) {
qla2x00_update_fcports ( vha ) ;
clear_bit ( FCPORT_UPDATE_NEEDED , & vha - > dpc_flags ) ;
}
if ( ( test_and_clear_bit ( RELOGIN_NEEDED , & vha - > dpc_flags ) ) & &
! test_bit ( LOOP_RESYNC_NEEDED , & vha - > dpc_flags ) & &
atomic_read ( & vha - > loop_state ) ! = LOOP_DOWN ) {
DEBUG ( printk ( " scsi(%ld): qla2x00_port_login() \n " ,
vha - > host_no ) ) ;
qla2x00_relogin ( vha ) ;
DEBUG ( printk ( " scsi(%ld): qla2x00_port_login - end \n " ,
vha - > host_no ) ) ;
}
2007-07-06 00:16:51 +04:00
if ( test_and_clear_bit ( RESET_MARKER_NEEDED , & vha - > dpc_flags ) & &
( ! ( test_and_set_bit ( RESET_ACTIVE , & vha - > dpc_flags ) ) ) ) {
clear_bit ( RESET_ACTIVE , & vha - > dpc_flags ) ;
}
2008-12-10 03:45:39 +03:00
if ( test_and_clear_bit ( LOOP_RESYNC_NEEDED , & vha - > dpc_flags ) ) {
2007-07-06 00:16:51 +04:00
if ( ! ( test_and_set_bit ( LOOP_RESYNC_ACTIVE , & vha - > dpc_flags ) ) ) {
qla2x00_loop_resync ( vha ) ;
clear_bit ( LOOP_RESYNC_ACTIVE , & vha - > dpc_flags ) ;
}
}
return 0 ;
}
void
2008-11-06 21:40:19 +03:00
qla2x00_do_dpc_all_vps ( scsi_qla_host_t * vha )
2007-07-06 00:16:51 +04:00
{
int ret ;
2008-11-06 21:40:19 +03:00
struct qla_hw_data * ha = vha - > hw ;
scsi_qla_host_t * vp ;
2009-03-05 22:07:02 +03:00
struct scsi_qla_host * tvp ;
2007-07-06 00:16:51 +04:00
2008-11-06 21:40:19 +03:00
if ( vha - > vp_idx )
2007-07-06 00:16:51 +04:00
return ;
if ( list_empty ( & ha - > vp_list ) )
return ;
2008-11-06 21:40:19 +03:00
clear_bit ( VP_DPC_NEEDED , & vha - > dpc_flags ) ;
2007-07-06 00:16:51 +04:00
2009-03-05 22:07:02 +03:00
list_for_each_entry_safe ( vp , tvp , & ha - > vp_list , list ) {
2008-11-06 21:40:19 +03:00
if ( vp - > vp_idx )
ret = qla2x00_do_dpc_vp ( vp ) ;
2007-07-06 00:16:51 +04:00
}
}
int
qla24xx_vport_create_req_sanity_check ( struct fc_vport * fc_vport )
{
2008-11-06 21:40:19 +03:00
scsi_qla_host_t * base_vha = shost_priv ( fc_vport - > shost ) ;
struct qla_hw_data * ha = base_vha - > hw ;
2007-07-06 00:16:51 +04:00
scsi_qla_host_t * vha ;
uint8_t port_name [ WWN_SIZE ] ;
if ( fc_vport - > roles ! = FC_PORT_ROLE_FCP_INITIATOR )
return VPCERR_UNSUPPORTED ;
/* Check up the F/W and H/W support NPIV */
if ( ! ha - > flags . npiv_supported )
return VPCERR_UNSUPPORTED ;
/* Check up whether npiv supported switch presented */
if ( ! ( ha - > switch_cap & FLOGI_MID_SUPPORT ) )
return VPCERR_NO_FABRIC_SUPP ;
/* Check up unique WWPN */
u64_to_wwn ( fc_vport - > port_name , port_name ) ;
2008-11-06 21:40:19 +03:00
if ( ! memcmp ( port_name , base_vha - > port_name , WWN_SIZE ) )
2008-01-17 20:02:14 +03:00
return VPCERR_BAD_WWN ;
2007-07-06 00:16:51 +04:00
vha = qla24xx_find_vhost_by_name ( ha , port_name ) ;
if ( vha )
return VPCERR_BAD_WWN ;
/* Check up max-npiv-supports */
if ( ha - > num_vhosts > ha - > max_npiv_vports ) {
2007-11-12 21:30:58 +03:00
DEBUG15 ( printk ( " scsi(%ld): num_vhosts %ud is bigger than "
2008-11-06 21:40:19 +03:00
" max_npv_vports %ud. \n " , base_vha - > host_no ,
2007-11-12 21:30:58 +03:00
ha - > num_vhosts , ha - > max_npiv_vports ) ) ;
2007-07-06 00:16:51 +04:00
return VPCERR_UNSUPPORTED ;
}
return 0 ;
}
scsi_qla_host_t *
qla24xx_create_vhost ( struct fc_vport * fc_vport )
{
2008-11-06 21:40:19 +03:00
scsi_qla_host_t * base_vha = shost_priv ( fc_vport - > shost ) ;
struct qla_hw_data * ha = base_vha - > hw ;
2007-07-06 00:16:51 +04:00
scsi_qla_host_t * vha ;
2008-11-06 21:40:19 +03:00
struct scsi_host_template * sht = & qla24xx_driver_template ;
2007-07-06 00:16:51 +04:00
struct Scsi_Host * host ;
2008-11-06 21:40:19 +03:00
vha = qla2x00_create_host ( sht , ha ) ;
if ( ! vha ) {
DEBUG ( printk ( " qla2xxx: scsi_host_alloc() failed for vport \n " ) ) ;
2007-07-06 00:16:51 +04:00
return ( NULL ) ;
}
2008-11-06 21:40:19 +03:00
host = vha - > host ;
2007-07-06 00:16:51 +04:00
fc_vport - > dd_data = vha ;
/* New host info */
u64_to_wwn ( fc_vport - > node_name , vha - > node_name ) ;
u64_to_wwn ( fc_vport - > port_name , vha - > port_name ) ;
vha - > fc_vport = fc_vport ;
vha - > device_flags = 0 ;
vha - > vp_idx = qla24xx_allocate_vp_id ( vha ) ;
if ( vha - > vp_idx > ha - > max_npiv_vports ) {
DEBUG15 ( printk ( " scsi(%ld): Couldn't allocate vp_id. \n " ,
vha - > host_no ) ) ;
2008-11-06 21:40:19 +03:00
goto create_vhost_failed ;
2007-07-06 00:16:51 +04:00
}
vha - > mgmt_svr_loop_id = 10 + vha - > vp_idx ;
vha - > dpc_flags = 0L ;
set_bit ( REGISTER_FDMI_NEEDED , & vha - > dpc_flags ) ;
set_bit ( REGISTER_FC4_NEEDED , & vha - > dpc_flags ) ;
/*
* To fix the issue of processing a parent ' s RSCN for the vport before
* its SCR is complete .
*/
set_bit ( VP_SCR_NEEDED , & vha - > vp_flags ) ;
atomic_set ( & vha - > loop_state , LOOP_DOWN ) ;
atomic_set ( & vha - > loop_down_timer , LOOP_DOWN_TIME ) ;
qla2x00_start_timer ( vha , qla2x00_timer , WATCH_INTERVAL ) ;
2009-02-09 07:50:13 +03:00
memset ( vha - > req_ques , 0 , sizeof ( vha - > req_ques ) ) ;
2008-12-10 03:45:39 +03:00
vha - > req_ques [ 0 ] = ha - > req_q_map [ 0 ] - > id ;
host - > can_queue = ha - > req_q_map [ 0 ] - > length + 128 ;
2007-07-06 00:16:51 +04:00
host - > this_id = 255 ;
host - > cmd_per_lun = 3 ;
host - > max_cmd_len = MAX_CMDSZ ;
host - > max_channel = MAX_BUSES - 1 ;
host - > max_lun = MAX_LUNS ;
2008-07-11 03:55:51 +04:00
host - > unique_id = host - > host_no ;
2007-07-06 00:16:51 +04:00
host - > max_id = MAX_TARGETS_2200 ;
host - > transportt = qla2xxx_transport_vport_template ;
DEBUG15 ( printk ( " DEBUG: detect vport hba %ld at address = %p \n " ,
vha - > host_no , vha ) ) ;
vha - > flags . init_done = 1 ;
return vha ;
2008-11-06 21:40:19 +03:00
create_vhost_failed :
2007-07-06 00:16:51 +04:00
return NULL ;
}
2008-12-10 03:45:39 +03:00
static void
qla25xx_free_req_que ( struct scsi_qla_host * vha , struct req_que * req )
{
struct qla_hw_data * ha = vha - > hw ;
uint16_t que_id = req - > id ;
dma_free_coherent ( & ha - > pdev - > dev , ( req - > length + 1 ) *
sizeof ( request_t ) , req - > ring , req - > dma ) ;
req - > ring = NULL ;
req - > dma = 0 ;
if ( que_id ) {
ha - > req_q_map [ que_id ] = NULL ;
mutex_lock ( & ha - > vport_lock ) ;
clear_bit ( que_id , ha - > req_qid_map ) ;
mutex_unlock ( & ha - > vport_lock ) ;
}
kfree ( req ) ;
req = NULL ;
}
static void
qla25xx_free_rsp_que ( struct scsi_qla_host * vha , struct rsp_que * rsp )
{
struct qla_hw_data * ha = vha - > hw ;
uint16_t que_id = rsp - > id ;
if ( rsp - > msix & & rsp - > msix - > have_irq ) {
free_irq ( rsp - > msix - > vector , rsp ) ;
rsp - > msix - > have_irq = 0 ;
rsp - > msix - > rsp = NULL ;
}
dma_free_coherent ( & ha - > pdev - > dev , ( rsp - > length + 1 ) *
sizeof ( response_t ) , rsp - > ring , rsp - > dma ) ;
rsp - > ring = NULL ;
rsp - > dma = 0 ;
if ( que_id ) {
ha - > rsp_q_map [ que_id ] = NULL ;
mutex_lock ( & ha - > vport_lock ) ;
clear_bit ( que_id , ha - > rsp_qid_map ) ;
mutex_unlock ( & ha - > vport_lock ) ;
}
kfree ( rsp ) ;
rsp = NULL ;
}
int
qla25xx_delete_req_que ( struct scsi_qla_host * vha , struct req_que * req )
{
int ret = - 1 ;
if ( req ) {
req - > options | = BIT_0 ;
2009-02-09 07:50:11 +03:00
ret = qla25xx_init_req_que ( vha , req ) ;
2008-12-10 03:45:39 +03:00
}
if ( ret = = QLA_SUCCESS )
qla25xx_free_req_que ( vha , req ) ;
return ret ;
}
int
qla25xx_delete_rsp_que ( struct scsi_qla_host * vha , struct rsp_que * rsp )
{
int ret = - 1 ;
if ( rsp ) {
rsp - > options | = BIT_0 ;
2009-02-09 07:50:11 +03:00
ret = qla25xx_init_rsp_que ( vha , rsp ) ;
2008-12-10 03:45:39 +03:00
}
if ( ret = = QLA_SUCCESS )
qla25xx_free_rsp_que ( vha , rsp ) ;
return ret ;
}
int qla25xx_update_req_que ( struct scsi_qla_host * vha , uint8_t que , uint8_t qos )
{
int ret = 0 ;
struct qla_hw_data * ha = vha - > hw ;
struct req_que * req = ha - > req_q_map [ que ] ;
req - > options | = BIT_3 ;
req - > qos = qos ;
2009-02-09 07:50:11 +03:00
ret = qla25xx_init_req_que ( vha , req ) ;
2008-12-10 03:45:39 +03:00
if ( ret ! = QLA_SUCCESS )
DEBUG2_17 ( printk ( KERN_WARNING " %s failed \n " , __func__ ) ) ;
/* restore options bit */
req - > options & = ~ BIT_3 ;
return ret ;
}
/* Delete all queues for a given vhost */
int
qla25xx_delete_queues ( struct scsi_qla_host * vha , uint8_t que_no )
{
int cnt , ret = 0 ;
struct req_que * req = NULL ;
struct rsp_que * rsp = NULL ;
struct qla_hw_data * ha = vha - > hw ;
if ( que_no ) {
/* Delete request queue */
req = ha - > req_q_map [ que_no ] ;
if ( req ) {
rsp = req - > rsp ;
ret = qla25xx_delete_req_que ( vha , req ) ;
if ( ret ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha ,
" Couldn't delete req que %d \n " , req - > id ) ;
return ret ;
}
/* Delete associated response queue */
if ( rsp ) {
ret = qla25xx_delete_rsp_que ( vha , rsp ) ;
if ( ret ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha ,
" Couldn't delete rsp que %d \n " ,
rsp - > id ) ;
return ret ;
}
}
}
} else { /* delete all queues of this host */
for ( cnt = 0 ; cnt < QLA_MAX_HOST_QUES ; cnt + + ) {
/* Delete request queues */
req = ha - > req_q_map [ vha - > req_ques [ cnt ] ] ;
if ( req & & req - > id ) {
rsp = req - > rsp ;
ret = qla25xx_delete_req_que ( vha , req ) ;
if ( ret ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha ,
" Couldn't delete req que %d \n " ,
vha - > req_ques [ cnt ] ) ;
return ret ;
}
vha - > req_ques [ cnt ] = ha - > req_q_map [ 0 ] - > id ;
/* Delete associated response queue */
if ( rsp & & rsp - > id ) {
ret = qla25xx_delete_rsp_que ( vha , rsp ) ;
if ( ret ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha ,
" Couldn't delete rsp que %d \n " ,
rsp - > id ) ;
return ret ;
}
}
}
}
}
qla_printk ( KERN_INFO , ha , " Queues deleted for vport:%d \n " ,
vha - > vp_idx ) ;
return ret ;
}
int
qla25xx_create_req_que ( struct qla_hw_data * ha , uint16_t options ,
uint8_t vp_idx , uint16_t rid , uint8_t rsp_que , uint8_t qos )
{
int ret = 0 ;
struct req_que * req = NULL ;
struct scsi_qla_host * base_vha = pci_get_drvdata ( ha - > pdev ) ;
uint16_t que_id = 0 ;
2009-03-24 19:07:55 +03:00
device_reg_t __iomem * reg ;
2008-12-10 03:45:39 +03:00
req = kzalloc ( sizeof ( struct req_que ) , GFP_KERNEL ) ;
if ( req = = NULL ) {
qla_printk ( KERN_WARNING , ha , " could not allocate memory "
" for request que \n " ) ;
goto que_failed ;
}
req - > length = REQUEST_ENTRY_CNT_24XX ;
req - > ring = dma_alloc_coherent ( & ha - > pdev - > dev ,
( req - > length + 1 ) * sizeof ( request_t ) ,
& req - > dma , GFP_KERNEL ) ;
if ( req - > ring = = NULL ) {
qla_printk ( KERN_WARNING , ha ,
" Memory Allocation failed - request_ring \n " ) ;
goto que_failed ;
}
mutex_lock ( & ha - > vport_lock ) ;
que_id = find_first_zero_bit ( ha - > req_qid_map , ha - > max_queues ) ;
if ( que_id > = ha - > max_queues ) {
mutex_unlock ( & ha - > vport_lock ) ;
qla_printk ( KERN_INFO , ha , " No resources to create "
" additional request queue \n " ) ;
goto que_failed ;
}
set_bit ( que_id , ha - > req_qid_map ) ;
ha - > req_q_map [ que_id ] = req ;
req - > rid = rid ;
req - > vp_idx = vp_idx ;
req - > qos = qos ;
2009-01-05 22:18:10 +03:00
if ( ha - > rsp_q_map [ rsp_que ] ) {
2008-12-10 03:45:39 +03:00
req - > rsp = ha - > rsp_q_map [ rsp_que ] ;
2009-01-05 22:18:10 +03:00
req - > rsp - > req = req ;
}
2008-12-10 03:45:39 +03:00
/* Use alternate PCI bus number */
if ( MSB ( req - > rid ) )
options | = BIT_4 ;
/* Use alternate PCI devfn */
if ( LSB ( req - > rid ) )
options | = BIT_5 ;
req - > options = options ;
req - > ring_ptr = req - > ring ;
req - > ring_index = 0 ;
req - > cnt = req - > length ;
req - > id = que_id ;
2009-03-24 19:07:55 +03:00
reg = ISP_QUE_REG ( ha , que_id ) ;
req - > req_q_in = & reg - > isp25mq . req_q_in ;
req - > req_q_out = & reg - > isp25mq . req_q_out ;
2009-01-09 02:41:08 +03:00
req - > max_q_depth = ha - > req_q_map [ 0 ] - > max_q_depth ;
2008-12-10 03:45:39 +03:00
mutex_unlock ( & ha - > vport_lock ) ;
2009-02-09 07:50:11 +03:00
ret = qla25xx_init_req_que ( base_vha , req ) ;
2008-12-10 03:45:39 +03:00
if ( ret ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha , " %s failed \n " , __func__ ) ;
mutex_lock ( & ha - > vport_lock ) ;
clear_bit ( que_id , ha - > req_qid_map ) ;
mutex_unlock ( & ha - > vport_lock ) ;
goto que_failed ;
}
return req - > id ;
que_failed :
qla25xx_free_req_que ( base_vha , req ) ;
return 0 ;
}
/* create response queue */
int
qla25xx_create_rsp_que ( struct qla_hw_data * ha , uint16_t options ,
uint8_t vp_idx , uint16_t rid )
{
int ret = 0 ;
struct rsp_que * rsp = NULL ;
struct scsi_qla_host * base_vha = pci_get_drvdata ( ha - > pdev ) ;
2009-03-24 19:07:55 +03:00
uint16_t que_id = 0 ;
device_reg_t __iomem * reg ;
2008-12-10 03:45:39 +03:00
rsp = kzalloc ( sizeof ( struct rsp_que ) , GFP_KERNEL ) ;
if ( rsp = = NULL ) {
qla_printk ( KERN_WARNING , ha , " could not allocate memory for "
" response que \n " ) ;
goto que_failed ;
}
rsp - > length = RESPONSE_ENTRY_CNT_2300 ;
rsp - > ring = dma_alloc_coherent ( & ha - > pdev - > dev ,
( rsp - > length + 1 ) * sizeof ( response_t ) ,
& rsp - > dma , GFP_KERNEL ) ;
if ( rsp - > ring = = NULL ) {
qla_printk ( KERN_WARNING , ha ,
" Memory Allocation failed - response_ring \n " ) ;
goto que_failed ;
}
mutex_lock ( & ha - > vport_lock ) ;
que_id = find_first_zero_bit ( ha - > rsp_qid_map , ha - > max_queues ) ;
if ( que_id > = ha - > max_queues ) {
mutex_unlock ( & ha - > vport_lock ) ;
qla_printk ( KERN_INFO , ha , " No resources to create "
" additional response queue \n " ) ;
goto que_failed ;
}
set_bit ( que_id , ha - > rsp_qid_map ) ;
if ( ha - > flags . msix_enabled )
rsp - > msix = & ha - > msix_entries [ que_id + 1 ] ;
else
qla_printk ( KERN_WARNING , ha , " msix not enabled \n " ) ;
ha - > rsp_q_map [ que_id ] = rsp ;
rsp - > rid = rid ;
rsp - > vp_idx = vp_idx ;
rsp - > hw = ha ;
/* Use alternate PCI bus number */
if ( MSB ( rsp - > rid ) )
options | = BIT_4 ;
/* Use alternate PCI devfn */
if ( LSB ( rsp - > rid ) )
options | = BIT_5 ;
rsp - > options = options ;
rsp - > ring_ptr = rsp - > ring ;
rsp - > ring_index = 0 ;
rsp - > id = que_id ;
2009-03-24 19:07:55 +03:00
reg = ISP_QUE_REG ( ha , que_id ) ;
rsp - > rsp_q_in = & reg - > isp25mq . rsp_q_in ;
rsp - > rsp_q_out = & reg - > isp25mq . rsp_q_out ;
2008-12-10 03:45:39 +03:00
mutex_unlock ( & ha - > vport_lock ) ;
ret = qla25xx_request_irq ( rsp ) ;
if ( ret )
goto que_failed ;
2009-02-09 07:50:11 +03:00
ret = qla25xx_init_rsp_que ( base_vha , rsp ) ;
2008-12-10 03:45:39 +03:00
if ( ret ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha , " %s failed \n " , __func__ ) ;
mutex_lock ( & ha - > vport_lock ) ;
clear_bit ( que_id , ha - > rsp_qid_map ) ;
mutex_unlock ( & ha - > vport_lock ) ;
goto que_failed ;
}
qla2x00_init_response_q_entries ( rsp ) ;
return rsp - > id ;
que_failed :
qla25xx_free_rsp_que ( base_vha , rsp ) ;
return 0 ;
}
int
qla25xx_create_queues ( struct scsi_qla_host * vha , uint8_t qos )
{
uint16_t options = 0 ;
uint8_t ret = 0 ;
struct qla_hw_data * ha = vha - > hw ;
options | = BIT_1 ;
ret = qla25xx_create_rsp_que ( ha , options , vha - > vp_idx , 0 ) ;
if ( ! ret ) {
qla_printk ( KERN_WARNING , ha , " Response Que create failed \n " ) ;
return ret ;
} else
qla_printk ( KERN_INFO , ha , " Response Que:%d created. \n " , ret ) ;
options = 0 ;
if ( qos & BIT_7 )
options | = BIT_8 ;
ret = qla25xx_create_req_que ( ha , options , vha - > vp_idx , 0 , ret ,
qos & ~ BIT_7 ) ;
if ( ret ) {
vha - > req_ques [ 0 ] = ret ;
qla_printk ( KERN_INFO , ha , " Request Que:%d created. \n " , ret ) ;
} else
qla_printk ( KERN_WARNING , ha , " Request Que create failed \n " ) ;
return ret ;
}