2007-06-18 04:56:38 +04:00
/*******************************************************************
2005-04-18 01:05:31 +04:00
* This file is part of the Emulex Linux Device Driver for *
2005-06-25 18:34:39 +04:00
* Fibre Channel Host Bus Adapters . *
2008-02-09 02:49:26 +03:00
* Copyright ( C ) 2004 - 2008 Emulex . All rights reserved . *
2005-06-25 18:34:39 +04:00
* EMULEX and SLI are trademarks of Emulex . *
2005-04-18 01:05:31 +04:00
* www . emulex . com *
2005-06-25 18:34:39 +04:00
* Portions Copyright ( C ) 2004 - 2005 Christoph Hellwig *
2005-04-18 01:05:31 +04:00
* *
* This program is free software ; you can redistribute it and / or *
2005-06-25 18:34:39 +04:00
* modify it under the terms of version 2 of the GNU General *
* Public License as published by the Free Software Foundation . *
* This program is distributed in the hope that it will be useful . *
* ALL EXPRESS OR IMPLIED CONDITIONS , REPRESENTATIONS AND *
* WARRANTIES , INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY , *
* FITNESS FOR A PARTICULAR PURPOSE , OR NON - INFRINGEMENT , ARE *
* DISCLAIMED , EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
* TO BE LEGALLY INVALID . See the GNU General Public License for *
* more details , a copy of which can be found in the file COPYING *
* included with this package . *
2005-04-18 01:05:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/blkdev.h>
# include <linux/pci.h>
# include <linux/interrupt.h>
2005-08-10 23:03:09 +04:00
# include <scsi/scsi.h>
2005-04-18 01:05:31 +04:00
# include <scsi/scsi_device.h>
# include <scsi/scsi_host.h>
# include <scsi/scsi_transport_fc.h>
# include "lpfc_hw.h"
# include "lpfc_sli.h"
# include "lpfc_disc.h"
# include "lpfc_scsi.h"
# include "lpfc.h"
# include "lpfc_logmsg.h"
# include "lpfc_crtn.h"
2007-06-18 04:56:38 +04:00
# include "lpfc_vport.h"
2007-06-18 04:56:39 +04:00
# include "lpfc_debugfs.h"
2005-04-18 01:05:31 +04:00
/* Called to verify a rcv'ed ADISC was intended for us. */
static int
2007-06-18 04:56:36 +04:00
lpfc_check_adisc ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
struct lpfc_name * nn , struct lpfc_name * pn )
2005-04-18 01:05:31 +04:00
{
/* Compare the ADISC rsp WWNN / WWPN matches our internal node
* table entry for that node .
*/
2007-06-18 04:56:36 +04:00
if ( memcmp ( nn , & ndlp - > nlp_nodename , sizeof ( struct lpfc_name ) ) )
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
if ( memcmp ( pn , & ndlp - > nlp_portname , sizeof ( struct lpfc_name ) ) )
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
/* we match, return success */
2006-03-01 03:25:23 +03:00
return 1 ;
2005-04-18 01:05:31 +04:00
}
int
2007-06-18 04:56:36 +04:00
lpfc_check_sparm ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
struct serv_parm * sp , uint32_t class )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
volatile struct serv_parm * hsp = & vport - > fc_sparam ;
2005-11-28 19:41:24 +03:00
uint16_t hsp_value , ssp_value = 0 ;
/*
* The receive data field size and buffer - to - buffer receive data field
* size entries are 16 bits but are represented as two 8 - bit fields in
* the driver data structure to account for rsvd bits and other control
* bits . Reconstruct and compare the fields as a 16 - bit values before
* correcting the byte values .
*/
2005-04-18 01:05:31 +04:00
if ( sp - > cls1 . classValid ) {
2005-11-28 19:41:24 +03:00
hsp_value = ( hsp - > cls1 . rcvDataSizeMsb < < 8 ) |
hsp - > cls1 . rcvDataSizeLsb ;
ssp_value = ( sp - > cls1 . rcvDataSizeMsb < < 8 ) |
sp - > cls1 . rcvDataSizeLsb ;
2007-06-18 04:56:38 +04:00
if ( ! ssp_value )
goto bad_service_param ;
2005-11-28 19:41:24 +03:00
if ( ssp_value > hsp_value ) {
2005-04-18 01:05:31 +04:00
sp - > cls1 . rcvDataSizeLsb = hsp - > cls1 . rcvDataSizeLsb ;
2005-11-28 19:41:24 +03:00
sp - > cls1 . rcvDataSizeMsb = hsp - > cls1 . rcvDataSizeMsb ;
}
2005-04-18 01:05:31 +04:00
} else if ( class = = CLASS1 ) {
2007-06-18 04:56:38 +04:00
goto bad_service_param ;
2005-04-18 01:05:31 +04:00
}
if ( sp - > cls2 . classValid ) {
2005-11-28 19:41:24 +03:00
hsp_value = ( hsp - > cls2 . rcvDataSizeMsb < < 8 ) |
hsp - > cls2 . rcvDataSizeLsb ;
ssp_value = ( sp - > cls2 . rcvDataSizeMsb < < 8 ) |
sp - > cls2 . rcvDataSizeLsb ;
2007-06-18 04:56:38 +04:00
if ( ! ssp_value )
goto bad_service_param ;
2005-11-28 19:41:24 +03:00
if ( ssp_value > hsp_value ) {
2005-04-18 01:05:31 +04:00
sp - > cls2 . rcvDataSizeLsb = hsp - > cls2 . rcvDataSizeLsb ;
2005-11-28 19:41:24 +03:00
sp - > cls2 . rcvDataSizeMsb = hsp - > cls2 . rcvDataSizeMsb ;
}
2005-04-18 01:05:31 +04:00
} else if ( class = = CLASS2 ) {
2007-06-18 04:56:38 +04:00
goto bad_service_param ;
2005-04-18 01:05:31 +04:00
}
if ( sp - > cls3 . classValid ) {
2005-11-28 19:41:24 +03:00
hsp_value = ( hsp - > cls3 . rcvDataSizeMsb < < 8 ) |
hsp - > cls3 . rcvDataSizeLsb ;
ssp_value = ( sp - > cls3 . rcvDataSizeMsb < < 8 ) |
sp - > cls3 . rcvDataSizeLsb ;
2007-06-18 04:56:38 +04:00
if ( ! ssp_value )
goto bad_service_param ;
2005-11-28 19:41:24 +03:00
if ( ssp_value > hsp_value ) {
2005-04-18 01:05:31 +04:00
sp - > cls3 . rcvDataSizeLsb = hsp - > cls3 . rcvDataSizeLsb ;
2005-11-28 19:41:24 +03:00
sp - > cls3 . rcvDataSizeMsb = hsp - > cls3 . rcvDataSizeMsb ;
}
2005-04-18 01:05:31 +04:00
} else if ( class = = CLASS3 ) {
2007-06-18 04:56:38 +04:00
goto bad_service_param ;
2005-04-18 01:05:31 +04:00
}
2005-11-28 19:41:24 +03:00
/*
* Preserve the upper four bits of the MSB from the PLOGI response .
* These bits contain the Buffer - to - Buffer State Change Number
* from the target and need to be passed to the FW .
*/
hsp_value = ( hsp - > cmn . bbRcvSizeMsb < < 8 ) | hsp - > cmn . bbRcvSizeLsb ;
ssp_value = ( sp - > cmn . bbRcvSizeMsb < < 8 ) | sp - > cmn . bbRcvSizeLsb ;
if ( ssp_value > hsp_value ) {
2005-04-18 01:05:31 +04:00
sp - > cmn . bbRcvSizeLsb = hsp - > cmn . bbRcvSizeLsb ;
2005-11-28 19:41:24 +03:00
sp - > cmn . bbRcvSizeMsb = ( sp - > cmn . bbRcvSizeMsb & 0xF0 ) |
( hsp - > cmn . bbRcvSizeMsb & 0x0F ) ;
}
2005-04-18 01:05:31 +04:00
memcpy ( & ndlp - > nlp_nodename , & sp - > nodeName , sizeof ( struct lpfc_name ) ) ;
memcpy ( & ndlp - > nlp_portname , & sp - > portName , sizeof ( struct lpfc_name ) ) ;
2005-11-28 19:41:24 +03:00
return 1 ;
2007-06-18 04:56:38 +04:00
bad_service_param :
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_DISCOVERY ,
" 0207 Device %x "
" (%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
" invalid service parameters. Ignoring device. \n " ,
ndlp - > nlp_DID ,
sp - > nodeName . u . wwn [ 0 ] , sp - > nodeName . u . wwn [ 1 ] ,
sp - > nodeName . u . wwn [ 2 ] , sp - > nodeName . u . wwn [ 3 ] ,
sp - > nodeName . u . wwn [ 4 ] , sp - > nodeName . u . wwn [ 5 ] ,
sp - > nodeName . u . wwn [ 6 ] , sp - > nodeName . u . wwn [ 7 ] ) ;
2007-06-18 04:56:38 +04:00
return 0 ;
2005-04-18 01:05:31 +04:00
}
static void *
2007-06-18 04:56:36 +04:00
lpfc_check_elscmpl_iocb ( struct lpfc_hba * phba , struct lpfc_iocbq * cmdiocb ,
2007-06-18 04:56:38 +04:00
struct lpfc_iocbq * rspiocb )
2005-04-18 01:05:31 +04:00
{
struct lpfc_dmabuf * pcmd , * prsp ;
uint32_t * lp ;
void * ptr = NULL ;
IOCB_t * irsp ;
irsp = & rspiocb - > iocb ;
pcmd = ( struct lpfc_dmabuf * ) cmdiocb - > context2 ;
/* For lpfc_els_abort, context2 could be zero'ed to delay
* freeing associated memory till after ABTS completes .
*/
if ( pcmd ) {
prsp = list_get_first ( & pcmd - > list , struct lpfc_dmabuf ,
list ) ;
if ( prsp ) {
lp = ( uint32_t * ) prsp - > virt ;
ptr = ( void * ) ( ( uint8_t * ) lp + sizeof ( uint32_t ) ) ;
}
2006-03-01 03:25:31 +03:00
} else {
2005-04-18 01:05:31 +04:00
/* Force ulpStatus error since we are returning NULL ptr */
if ( ! ( irsp - > ulpStatus ) ) {
irsp - > ulpStatus = IOSTAT_LOCAL_REJECT ;
irsp - > un . ulpWord [ 4 ] = IOERR_SLI_ABORTED ;
}
ptr = NULL ;
}
2006-03-01 03:25:23 +03:00
return ptr ;
2005-04-18 01:05:31 +04:00
}
/*
* Free resources / clean up outstanding I / Os
* associated with a LPFC_NODELIST entry . This
* routine effectively results in a " software abort " .
*/
int
2007-06-18 04:56:36 +04:00
lpfc_els_abort ( struct lpfc_hba * phba , struct lpfc_nodelist * ndlp )
2005-04-18 01:05:31 +04:00
{
2007-04-25 17:52:20 +04:00
LIST_HEAD ( completions ) ;
2007-06-18 04:56:36 +04:00
struct lpfc_sli * psli = & phba - > sli ;
struct lpfc_sli_ring * pring = & psli - > ring [ LPFC_ELS_RING ] ;
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * iocb , * next_iocb ;
2007-04-25 17:52:20 +04:00
IOCB_t * cmd ;
2005-04-18 01:05:31 +04:00
/* Abort outstanding I/O on NPort <nlp_DID> */
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( ndlp - > vport , KERN_INFO , LOG_DISCOVERY ,
" 0205 Abort outstanding I/O on NPort x%x "
" Data: x%x x%x x%x \n " ,
ndlp - > nlp_DID , ndlp - > nlp_flag , ndlp - > nlp_state ,
ndlp - > nlp_rpi ) ;
2007-06-18 04:56:38 +04:00
lpfc_fabric_abort_nport ( ndlp ) ;
2005-04-18 01:05:31 +04:00
/* First check the txq */
2007-06-18 04:56:36 +04:00
spin_lock_irq ( & phba - > hbalock ) ;
2007-04-25 17:52:20 +04:00
list_for_each_entry_safe ( iocb , next_iocb , & pring - > txq , list ) {
2007-06-18 04:56:39 +04:00
/* Check to see if iocb matches the nport we are looking for */
2007-04-25 17:52:20 +04:00
if ( lpfc_check_sli_ndlp ( phba , pring , iocb , ndlp ) ) {
2007-06-18 04:56:39 +04:00
/* It matches, so deque and call compl with anp error */
2007-04-25 17:52:20 +04:00
list_move_tail ( & iocb - > list , & completions ) ;
pring - > txq_cnt - - ;
2005-04-18 01:05:31 +04:00
}
2007-04-25 17:52:20 +04:00
}
2005-04-18 01:05:31 +04:00
/* Next check the txcmplq */
2007-04-25 17:51:38 +04:00
list_for_each_entry_safe ( iocb , next_iocb , & pring - > txcmplq , list ) {
2007-06-18 04:56:39 +04:00
/* Check to see if iocb matches the nport we are looking for */
2007-06-18 04:56:38 +04:00
if ( lpfc_check_sli_ndlp ( phba , pring , iocb , ndlp ) ) {
2007-04-25 17:51:38 +04:00
lpfc_sli_issue_abort_iotag ( phba , pring , iocb ) ;
2007-06-18 04:56:38 +04:00
}
2007-04-25 17:51:38 +04:00
}
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( & phba - > hbalock ) ;
2005-04-18 01:05:31 +04:00
2007-04-25 17:52:20 +04:00
while ( ! list_empty ( & completions ) ) {
iocb = list_get_first ( & completions , struct lpfc_iocbq , list ) ;
cmd = & iocb - > iocb ;
2007-06-18 04:56:38 +04:00
list_del_init ( & iocb - > list ) ;
2007-04-25 17:52:20 +04:00
2007-06-18 04:56:36 +04:00
if ( ! iocb - > iocb_cmpl )
lpfc_sli_release_iocbq ( phba , iocb ) ;
else {
2007-04-25 17:52:20 +04:00
cmd - > ulpStatus = IOSTAT_LOCAL_REJECT ;
cmd - > un . ulpWord [ 4 ] = IOERR_SLI_ABORTED ;
( iocb - > iocb_cmpl ) ( phba , iocb , iocb ) ;
2007-06-18 04:56:36 +04:00
}
2007-04-25 17:52:20 +04:00
}
2005-04-18 01:05:31 +04:00
/* If we are delaying issuing an ELS command, cancel it */
2006-03-07 23:04:01 +03:00
if ( ndlp - > nlp_flag & NLP_DELAY_TMO )
2007-06-18 04:56:36 +04:00
lpfc_cancel_retry_delay_tmo ( phba - > pport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
}
static int
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
2007-06-18 04:56:38 +04:00
struct lpfc_iocbq * cmdiocb )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_hba * phba = vport - > phba ;
2005-04-18 01:05:31 +04:00
struct lpfc_dmabuf * pcmd ;
2008-02-09 02:49:26 +03:00
struct lpfc_work_evt * evtp ;
2005-04-18 01:05:31 +04:00
uint32_t * lp ;
IOCB_t * icmd ;
struct serv_parm * sp ;
LPFC_MBOXQ_t * mbox ;
struct ls_rjt stat ;
int rc ;
memset ( & stat , 0 , sizeof ( struct ls_rjt ) ) ;
2007-06-18 04:56:36 +04:00
if ( vport - > port_state < = LPFC_FLOGI ) {
2005-04-18 01:05:31 +04:00
/* Before responding to PLOGI, check for pt2pt mode.
* If we are pt2pt , with an outstanding FLOGI , abort
* the FLOGI and resend it first .
*/
2007-06-18 04:56:36 +04:00
if ( vport - > fc_flag & FC_PT2PT ) {
2007-06-18 04:56:38 +04:00
lpfc_els_abort_flogi ( phba ) ;
2007-06-18 04:56:36 +04:00
if ( ! ( vport - > fc_flag & FC_PT2PT_PLOGI ) ) {
2005-04-18 01:05:31 +04:00
/* If the other side is supposed to initiate
* the PLOGI anyway , just ACC it now and
* move on with discovery .
*/
phba - > fc_edtov = FF_DEF_EDTOV ;
phba - > fc_ratov = FF_DEF_RATOV ;
/* Start discovery - this should just do
CLEAR_LA */
2007-06-18 04:56:36 +04:00
lpfc_disc_start ( vport ) ;
2007-06-18 04:56:37 +04:00
} else
2007-06-18 04:56:36 +04:00
lpfc_initial_flogi ( vport ) ;
2006-03-01 03:25:31 +03:00
} else {
2005-04-18 01:05:31 +04:00
stat . un . b . lsRjtRsnCode = LSRJT_LOGICAL_BSY ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_NOTHING_MORE ;
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb ,
2007-06-18 04:56:39 +04:00
ndlp , NULL ) ;
2005-04-18 01:05:31 +04:00
return 0 ;
}
}
pcmd = ( struct lpfc_dmabuf * ) cmdiocb - > context2 ;
lp = ( uint32_t * ) pcmd - > virt ;
sp = ( struct serv_parm * ) ( ( uint8_t * ) lp + sizeof ( uint32_t ) ) ;
2007-10-27 21:37:53 +04:00
if ( wwn_to_u64 ( sp - > portName . u . wwn ) = = 0 ) {
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0140 PLOGI Reject: invalid nname \n " ) ;
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_INVALID_PNAME ;
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp ,
NULL ) ;
return 0 ;
}
if ( wwn_to_u64 ( sp - > nodeName . u . wwn ) = = 0 ) {
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0141 PLOGI Reject: invalid pname \n " ) ;
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_INVALID_NNAME ;
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp ,
NULL ) ;
return 0 ;
}
2007-06-18 04:56:36 +04:00
if ( ( lpfc_check_sparm ( vport , ndlp , sp , CLASS3 ) = = 0 ) ) {
2005-04-18 01:05:31 +04:00
/* Reject this request because invalid parameters */
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS ;
2007-06-18 04:56:39 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp ,
NULL ) ;
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
}
icmd = & cmdiocb - > iocb ;
/* PLOGI chkparm OK */
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_INFO , LOG_ELS ,
" 0114 PLOGI chkparm OK Data: x%x x%x x%x x%x \n " ,
ndlp - > nlp_DID , ndlp - > nlp_state , ndlp - > nlp_flag ,
ndlp - > nlp_rpi ) ;
2005-04-18 01:05:31 +04:00
2007-08-02 19:09:59 +04:00
if ( vport - > cfg_fcp_class = = 2 & & sp - > cls2 . classValid )
2005-04-18 01:05:31 +04:00
ndlp - > nlp_fcp_info | = CLASS2 ;
2007-06-18 04:56:37 +04:00
else
2005-04-18 01:05:31 +04:00
ndlp - > nlp_fcp_info | = CLASS3 ;
2007-06-18 04:56:36 +04:00
2005-04-18 01:05:31 +04:00
ndlp - > nlp_class_sup = 0 ;
if ( sp - > cls1 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS1 ;
if ( sp - > cls2 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS2 ;
if ( sp - > cls3 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS3 ;
if ( sp - > cls4 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS4 ;
ndlp - > nlp_maxframe =
( ( sp - > cmn . bbRcvSizeMsb & 0x0F ) < < 8 ) | sp - > cmn . bbRcvSizeLsb ;
/* no need to reg_login if we are already in one of these states */
2006-03-01 03:25:31 +03:00
switch ( ndlp - > nlp_state ) {
2005-04-18 01:05:31 +04:00
case NLP_STE_NPR_NODE :
if ( ! ( ndlp - > nlp_flag & NLP_NPR_ADISC ) )
break ;
case NLP_STE_REG_LOGIN_ISSUE :
case NLP_STE_PRLI_ISSUE :
case NLP_STE_UNMAPPED_NODE :
case NLP_STE_MAPPED_NODE :
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PLOGI , cmdiocb , ndlp , NULL ) ;
2006-03-01 03:25:23 +03:00
return 1 ;
2005-04-18 01:05:31 +04:00
}
2007-06-18 04:56:38 +04:00
if ( ( vport - > fc_flag & FC_PT2PT ) & &
! ( vport - > fc_flag & FC_PT2PT_PLOGI ) ) {
2005-04-18 01:05:31 +04:00
/* rcv'ed PLOGI decides what our NPortId will be */
2007-06-18 04:56:36 +04:00
vport - > fc_myDID = icmd - > un . rcvels . parmRo ;
2005-04-18 01:05:31 +04:00
mbox = mempool_alloc ( phba - > mbox_mem_pool , GFP_KERNEL ) ;
if ( mbox = = NULL )
goto out ;
lpfc_config_link ( phba , mbox ) ;
mbox - > mbox_cmpl = lpfc_sli_def_mbox_cmpl ;
2007-06-18 04:56:37 +04:00
mbox - > vport = vport ;
2007-10-27 21:37:25 +04:00
rc = lpfc_sli_issue_mbox ( phba , mbox , MBX_NOWAIT ) ;
2005-04-18 01:05:31 +04:00
if ( rc = = MBX_NOT_FINISHED ) {
2007-06-18 04:56:38 +04:00
mempool_free ( mbox , phba - > mbox_mem_pool ) ;
2005-04-18 01:05:31 +04:00
goto out ;
}
2007-06-18 04:56:36 +04:00
lpfc_can_disctmo ( vport ) ;
2005-04-18 01:05:31 +04:00
}
mbox = mempool_alloc ( phba - > mbox_mem_pool , GFP_KERNEL ) ;
2007-06-18 04:56:36 +04:00
if ( ! mbox )
2005-04-18 01:05:31 +04:00
goto out ;
2007-06-18 04:56:38 +04:00
rc = lpfc_reg_login ( phba , vport - > vpi , icmd - > un . rcvels . remoteID ,
( uint8_t * ) sp , mbox , 0 ) ;
2007-06-18 04:56:36 +04:00
if ( rc ) {
mempool_free ( mbox , phba - > mbox_mem_pool ) ;
2005-04-18 01:05:31 +04:00
goto out ;
}
/* ACC PLOGI rsp command needs to execute first,
* queue this mbox command to be processed later .
*/
mbox - > mbox_cmpl = lpfc_mbx_cmpl_reg_login ;
2007-04-25 17:53:01 +04:00
/*
* mbox - > context2 = lpfc_nlp_get ( ndlp ) deferred until mailbox
* command issued in lpfc_cmpl_els_acc ( ) .
*/
2007-06-18 04:56:36 +04:00
mbox - > vport = vport ;
spin_lock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_flag | = ( NLP_ACC_REGLOGIN | NLP_RCV_PLOGI ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
2006-08-17 19:57:58 +04:00
/*
* If there is an outstanding PLOGI issued , abort it before
* sending ACC rsp for received PLOGI . If pending plogi
* is not canceled here , the plogi will be rejected by
* remote port and will be retried . On a configuration with
* single discovery thread , this will cause a huge delay in
* discovery . Also this will cause multiple state machines
* running in parallel for this node .
*/
if ( ndlp - > nlp_state = = NLP_STE_PLOGI_ISSUE ) {
/* software abort outstanding PLOGI */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2006-08-17 19:57:58 +04:00
}
2007-06-18 04:56:39 +04:00
if ( ( vport - > port_type = = LPFC_NPIV_PORT & &
2007-08-02 19:09:59 +04:00
vport - > cfg_restrict_login ) ) {
2007-06-18 04:56:39 +04:00
/* In order to preserve RPIs, we want to cleanup
* the default RPI the firmware created to rcv
* this ELS request . The only way to do this is
* to register , then unregister the RPI .
*/
spin_lock_irq ( shost - > host_lock ) ;
ndlp - > nlp_flag | = NLP_RM_DFLT_RPI ;
spin_unlock_irq ( shost - > host_lock ) ;
stat . un . b . lsRjtRsnCode = LSRJT_INVALID_CMD ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_NOTHING_MORE ;
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb ,
ndlp , mbox ) ;
return 1 ;
}
2007-10-27 21:37:43 +04:00
/* If the remote NPort logs into us, before we can initiate
* discovery to them , cleanup the NPort from discovery accordingly .
*/
if ( ndlp - > nlp_state = = NLP_STE_NPR_NODE ) {
spin_lock_irq ( shost - > host_lock ) ;
ndlp - > nlp_flag & = ~ NLP_DELAY_TMO ;
spin_unlock_irq ( shost - > host_lock ) ;
del_timer_sync ( & ndlp - > nlp_delayfunc ) ;
ndlp - > nlp_last_elscmd = 0 ;
2008-02-09 02:49:26 +03:00
if ( ! list_empty ( & ndlp - > els_retry_evt . evt_listp ) ) {
2007-10-27 21:37:43 +04:00
list_del_init ( & ndlp - > els_retry_evt . evt_listp ) ;
2008-02-09 02:49:26 +03:00
/* Decrement ndlp reference count held for the
* delayed retry
*/
evtp = & ndlp - > els_retry_evt ;
lpfc_nlp_put ( ( struct lpfc_nodelist * ) evtp - > evt_arg1 ) ;
}
2007-10-27 21:37:43 +04:00
if ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) {
spin_lock_irq ( shost - > host_lock ) ;
ndlp - > nlp_flag & = ~ NLP_NPR_2B_DISC ;
spin_unlock_irq ( shost - > host_lock ) ;
2008-01-11 09:52:36 +03:00
if ( ( ndlp - > nlp_flag & NLP_ADISC_SND ) & &
( vport - > num_disc_nodes ) ) {
/* Check to see if there are more
* ADISCs to be sent
*/
lpfc_more_adisc ( vport ) ;
if ( ( vport - > num_disc_nodes = = 0 ) & &
( vport - > fc_npr_cnt ) )
lpfc_els_disc_plogi ( vport ) ;
if ( vport - > num_disc_nodes = = 0 ) {
spin_lock_irq ( shost - > host_lock ) ;
vport - > fc_flag & = ~ FC_NDISC_ACTIVE ;
spin_unlock_irq ( shost - > host_lock ) ;
lpfc_can_disctmo ( vport ) ;
lpfc_end_rscn ( vport ) ;
}
}
else if ( vport - > num_disc_nodes ) {
2007-10-27 21:37:43 +04:00
/* Check to see if there are more
* PLOGIs to be sent
*/
lpfc_more_plogi ( vport ) ;
if ( vport - > num_disc_nodes = = 0 ) {
spin_lock_irq ( shost - > host_lock ) ;
vport - > fc_flag & = ~ FC_NDISC_ACTIVE ;
spin_unlock_irq ( shost - > host_lock ) ;
lpfc_can_disctmo ( vport ) ;
lpfc_end_rscn ( vport ) ;
}
}
}
}
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PLOGI , cmdiocb , ndlp , mbox ) ;
2006-03-01 03:25:23 +03:00
return 1 ;
2005-04-18 01:05:31 +04:00
out :
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE ;
2007-06-18 04:56:39 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp , NULL ) ;
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
}
static int
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * cmdiocb )
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2005-04-18 01:05:31 +04:00
struct lpfc_dmabuf * pcmd ;
2007-06-18 04:56:36 +04:00
struct serv_parm * sp ;
struct lpfc_name * pnn , * ppn ;
2005-04-18 01:05:31 +04:00
struct ls_rjt stat ;
ADISC * ap ;
IOCB_t * icmd ;
uint32_t * lp ;
uint32_t cmd ;
pcmd = ( struct lpfc_dmabuf * ) cmdiocb - > context2 ;
lp = ( uint32_t * ) pcmd - > virt ;
cmd = * lp + + ;
if ( cmd = = ELS_CMD_ADISC ) {
ap = ( ADISC * ) lp ;
pnn = ( struct lpfc_name * ) & ap - > nodeName ;
ppn = ( struct lpfc_name * ) & ap - > portName ;
} else {
sp = ( struct serv_parm * ) lp ;
pnn = ( struct lpfc_name * ) & sp - > nodeName ;
ppn = ( struct lpfc_name * ) & sp - > portName ;
}
icmd = & cmdiocb - > iocb ;
2007-06-18 04:56:36 +04:00
if ( icmd - > ulpStatus = = 0 & & lpfc_check_adisc ( vport , ndlp , pnn , ppn ) ) {
2005-04-18 01:05:31 +04:00
if ( cmd = = ELS_CMD_ADISC ) {
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_adisc_acc ( vport , cmdiocb , ndlp ) ;
2006-03-01 03:25:31 +03:00
} else {
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PLOGI , cmdiocb , ndlp ,
2007-08-02 19:10:31 +04:00
NULL ) ;
2005-04-18 01:05:31 +04:00
}
2006-03-01 03:25:23 +03:00
return 1 ;
2005-04-18 01:05:31 +04:00
}
/* Reject this request because invalid parameters */
stat . un . b . lsRjtRsvd0 = 0 ;
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS ;
stat . un . b . vendorUnique = 0 ;
2007-06-18 04:56:39 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp , NULL ) ;
2005-04-18 01:05:31 +04:00
/* 1 sec timeout */
mod_timer ( & ndlp - > nlp_delayfunc , jiffies + HZ ) ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag | = NLP_DELAY_TMO ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_last_elscmd = ELS_CMD_PLOGI ;
ndlp - > nlp_prev_state = ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
}
static int
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
struct lpfc_iocbq * cmdiocb , uint32_t els_cmd )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
/* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
2005-04-18 01:05:31 +04:00
/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
* PLOGIs during LOGO storms from a device .
*/
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag | = NLP_LOGO_ACC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-04-15 19:53:05 +04:00
if ( els_cmd = = ELS_CMD_PRLO )
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PRLO , cmdiocb , ndlp , NULL ) ;
2006-04-15 19:53:05 +04:00
else
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_ACC , cmdiocb , ndlp , NULL ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
if ( ! ( ndlp - > nlp_type & NLP_FABRIC ) | |
2007-06-18 04:56:38 +04:00
( ndlp - > nlp_state = = NLP_STE_ADISC_ISSUE ) ) {
2005-04-18 01:05:31 +04:00
/* Only try to re-login if this is NOT a Fabric Node */
mod_timer ( & ndlp - > nlp_delayfunc , jiffies + HZ * 1 ) ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag | = NLP_DELAY_TMO ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_last_elscmd = ELS_CMD_PLOGI ;
2006-03-01 03:25:23 +03:00
}
2007-10-27 21:37:43 +04:00
ndlp - > nlp_prev_state = ndlp - > nlp_state ;
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
/* The driver has to wait until the ACC completes before it continues
* processing the LOGO . The action will resume in
* lpfc_cmpl_els_logo_acc routine . Since part of processing includes an
* unreg_login , the driver waits so the ACC does not get aborted .
*/
2006-03-01 03:25:23 +03:00
return 0 ;
2005-04-18 01:05:31 +04:00
}
static void
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
struct lpfc_iocbq * cmdiocb )
2005-04-18 01:05:31 +04:00
{
struct lpfc_dmabuf * pcmd ;
uint32_t * lp ;
PRLI * npr ;
struct fc_rport * rport = ndlp - > rport ;
u32 roles ;
pcmd = ( struct lpfc_dmabuf * ) cmdiocb - > context2 ;
lp = ( uint32_t * ) pcmd - > virt ;
npr = ( PRLI * ) ( ( uint8_t * ) lp + sizeof ( uint32_t ) ) ;
ndlp - > nlp_type & = ~ ( NLP_FCP_TARGET | NLP_FCP_INITIATOR ) ;
ndlp - > nlp_fcp_info & = ~ NLP_FCP_2_DEVICE ;
2007-06-18 04:56:38 +04:00
if ( npr - > prliType = = PRLI_FCP_TYPE ) {
2005-04-18 01:05:31 +04:00
if ( npr - > initiatorFunc )
ndlp - > nlp_type | = NLP_FCP_INITIATOR ;
if ( npr - > targetFunc )
ndlp - > nlp_type | = NLP_FCP_TARGET ;
if ( npr - > Retry )
ndlp - > nlp_fcp_info | = NLP_FCP_2_DEVICE ;
}
if ( rport ) {
/* We need to update the rport role values */
roles = FC_RPORT_ROLE_UNKNOWN ;
if ( ndlp - > nlp_type & NLP_FCP_INITIATOR )
roles | = FC_RPORT_ROLE_FCP_INITIATOR ;
if ( ndlp - > nlp_type & NLP_FCP_TARGET )
roles | = FC_RPORT_ROLE_FCP_TARGET ;
2007-06-18 04:56:39 +04:00
lpfc_debugfs_disc_trc ( vport , LPFC_DISC_TRC_RPORT ,
" rport rolechg: role:x%x did:x%x flg:x%x " ,
roles , ndlp - > nlp_DID , ndlp - > nlp_flag ) ;
2005-04-18 01:05:31 +04:00
fc_remote_port_rolechg ( rport , roles ) ;
}
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_disc_set_adisc ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2007-08-02 19:10:31 +04:00
if ( ! ndlp - > nlp_rpi ) {
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
return 0 ;
}
2005-04-18 01:05:31 +04:00
/* Check config parameter use-adisc or FCP-2 */
2007-08-02 19:09:59 +04:00
if ( ( vport - > cfg_use_adisc & & ( vport - > fc_flag & FC_RSCN_MODE ) ) | |
2007-06-18 04:56:38 +04:00
ndlp - > nlp_fcp_info & NLP_FCP_2_DEVICE ) {
spin_lock_irq ( shost - > host_lock ) ;
ndlp - > nlp_flag | = NLP_NPR_ADISC ;
spin_unlock_irq ( shost - > host_lock ) ;
return 1 ;
}
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
lpfc_unreg_rpi ( vport , ndlp ) ;
return 0 ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_disc_illegal ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_DISCOVERY ,
2008-02-09 02:49:26 +03:00
" 0271 Illegal State Transition: node x%x "
2007-08-02 19:10:09 +04:00
" event x%x, state x%x Data: x%x x%x \n " ,
ndlp - > nlp_DID , evt , ndlp - > nlp_state , ndlp - > nlp_rpi ,
ndlp - > nlp_flag ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
2007-10-27 21:37:43 +04:00
static uint32_t
lpfc_cmpl_plogi_illegal ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
{
/* This transition is only legal if we previously
* rcv ' ed a PLOGI . Since we don ' t want 2 discovery threads
* working on the same NPortID , do nothing for this thread
* to stop it .
*/
if ( ! ( ndlp - > nlp_flag & NLP_RCV_PLOGI ) ) {
lpfc_printf_vlog ( vport , KERN_ERR , LOG_DISCOVERY ,
2008-02-09 02:49:26 +03:00
" 0272 Illegal State Transition: node x%x "
2007-10-27 21:37:43 +04:00
" event x%x, state x%x Data: x%x x%x \n " ,
ndlp - > nlp_DID , evt , ndlp - > nlp_state , ndlp - > nlp_rpi ,
ndlp - > nlp_flag ) ;
}
return ndlp - > nlp_state ;
}
2005-04-18 01:05:31 +04:00
/* Start of Discovery State Machine routines */
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_unused_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
struct lpfc_iocbq * cmdiocb ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-06-18 04:56:36 +04:00
if ( lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ) {
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
2006-03-01 03:25:23 +03:00
return NLP_STE_FREED_NODE ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_els_unused_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
lpfc_issue_els_logo ( vport , ndlp , 0 ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_unused_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag | = NLP_LOGO_ACC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_ACC , cmdiocb , ndlp , NULL ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_logo_unused_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2006-03-01 03:25:23 +03:00
return NLP_STE_FREED_NODE ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_rm_unused_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2006-03-01 03:25:23 +03:00
return NLP_STE_FREED_NODE ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_plogi_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
2005-04-18 01:05:31 +04:00
void * arg , uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * cmdiocb = arg ;
2007-06-18 04:56:36 +04:00
struct lpfc_dmabuf * pcmd = ( struct lpfc_dmabuf * ) cmdiocb - > context2 ;
uint32_t * lp = ( uint32_t * ) pcmd - > virt ;
struct serv_parm * sp = ( struct serv_parm * ) ( lp + 1 ) ;
2005-04-18 01:05:31 +04:00
struct ls_rjt stat ;
int port_cmp ;
memset ( & stat , 0 , sizeof ( struct ls_rjt ) ) ;
/* For a PLOGI, we only accept if our portname is less
* than the remote portname .
*/
phba - > fc_stat . elsLogiCol + + ;
2007-06-18 04:56:36 +04:00
port_cmp = memcmp ( & vport - > fc_portname , & sp - > portName ,
2007-06-18 04:56:38 +04:00
sizeof ( struct lpfc_name ) ) ;
2005-04-18 01:05:31 +04:00
if ( port_cmp > = 0 ) {
/* Reject this request because the remote node will accept
ours */
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS ;
2007-06-18 04:56:39 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp ,
NULL ) ;
2006-03-01 03:25:31 +03:00
} else {
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ;
} /* If our portname was less */
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
}
2007-06-18 04:56:38 +04:00
static uint32_t
lpfc_rcv_prli_plogi_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
{
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
struct ls_rjt stat ;
memset ( & stat , 0 , sizeof ( struct ls_rjt ) ) ;
stat . un . b . lsRjtRsnCode = LSRJT_LOGICAL_BSY ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_NOTHING_MORE ;
2007-06-18 04:56:39 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp , NULL ) ;
2007-06-18 04:56:38 +04:00
return ndlp - > nlp_state ;
}
2006-03-01 03:25:23 +03:00
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_plogi_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2006-03-01 03:25:23 +03:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2006-03-01 03:25:23 +03:00
2007-06-18 04:56:38 +04:00
/* software abort outstanding PLOGI */
2007-06-18 04:56:36 +04:00
lpfc_els_abort ( vport - > phba , ndlp ) ;
2006-03-01 03:25:23 +03:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_els_plogi_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_hba * phba = vport - > phba ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
/* software abort outstanding PLOGI */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
if ( evt = = NLP_EVT_RCV_LOGO ) {
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_ACC , cmdiocb , ndlp , NULL ) ;
2006-03-01 03:25:31 +03:00
} else {
2007-06-18 04:56:36 +04:00
lpfc_issue_els_logo ( vport , ndlp , 0 ) ;
2005-04-18 01:05:31 +04:00
}
2007-06-18 04:56:36 +04:00
/* Put ndlp in npr state set plogi timer for 1 sec */
2006-03-01 03:25:28 +03:00
mod_timer ( & ndlp - > nlp_delayfunc , jiffies + HZ * 1 ) ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_flag | = NLP_DELAY_TMO ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_last_elscmd = ELS_CMD_PLOGI ;
ndlp - > nlp_prev_state = NLP_STE_PLOGI_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_plogi_plogi_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
2008-01-11 09:52:36 +03:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb , * rspiocb ;
2006-12-02 21:34:28 +03:00
struct lpfc_dmabuf * pcmd , * prsp , * mp ;
2005-04-18 01:05:31 +04:00
uint32_t * lp ;
IOCB_t * irsp ;
struct serv_parm * sp ;
LPFC_MBOXQ_t * mbox ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
rspiocb = cmdiocb - > context_un . rsp_iocb ;
if ( ndlp - > nlp_flag & NLP_ACC_REGLOGIN ) {
2006-03-01 03:25:28 +03:00
/* Recovery from PLOGI collision logic */
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
irsp = & rspiocb - > iocb ;
if ( irsp - > ulpStatus )
goto out ;
pcmd = ( struct lpfc_dmabuf * ) cmdiocb - > context2 ;
2007-06-18 04:56:36 +04:00
prsp = list_get_first ( & pcmd - > list , struct lpfc_dmabuf , list ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lp = ( uint32_t * ) prsp - > virt ;
2005-04-18 01:05:31 +04:00
sp = ( struct serv_parm * ) ( ( uint8_t * ) lp + sizeof ( uint32_t ) ) ;
2007-10-27 21:37:53 +04:00
if ( wwn_to_u64 ( sp - > portName . u . wwn ) = = 0 | |
wwn_to_u64 ( sp - > nodeName . u . wwn ) = = 0 ) {
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0142 PLOGI RSP: Invalid WWN. \n " ) ;
goto out ;
}
2007-06-18 04:56:36 +04:00
if ( ! lpfc_check_sparm ( vport , ndlp , sp , CLASS3 ) )
2005-04-18 01:05:31 +04:00
goto out ;
/* PLOGI chkparm OK */
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_INFO , LOG_ELS ,
" 0121 PLOGI chkparm OK Data: x%x x%x x%x x%x \n " ,
ndlp - > nlp_DID , ndlp - > nlp_state ,
ndlp - > nlp_flag , ndlp - > nlp_rpi ) ;
2007-08-02 19:09:59 +04:00
if ( vport - > cfg_fcp_class = = 2 & & ( sp - > cls2 . classValid ) )
2005-04-18 01:05:31 +04:00
ndlp - > nlp_fcp_info | = CLASS2 ;
2007-06-18 04:56:36 +04:00
else
2005-04-18 01:05:31 +04:00
ndlp - > nlp_fcp_info | = CLASS3 ;
2007-06-18 04:56:36 +04:00
2005-04-18 01:05:31 +04:00
ndlp - > nlp_class_sup = 0 ;
if ( sp - > cls1 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS1 ;
if ( sp - > cls2 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS2 ;
if ( sp - > cls3 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS3 ;
if ( sp - > cls4 . classValid )
ndlp - > nlp_class_sup | = FC_COS_CLASS4 ;
ndlp - > nlp_maxframe =
2007-06-18 04:56:36 +04:00
( ( sp - > cmn . bbRcvSizeMsb & 0x0F ) < < 8 ) | sp - > cmn . bbRcvSizeLsb ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
mbox = mempool_alloc ( phba - > mbox_mem_pool , GFP_KERNEL ) ;
2007-06-18 04:56:38 +04:00
if ( ! mbox ) {
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0133 PLOGI: no memory for reg_login "
2007-06-18 04:56:38 +04:00
" Data: x%x x%x x%x x%x \n " ,
ndlp - > nlp_DID , ndlp - > nlp_state ,
ndlp - > nlp_flag , ndlp - > nlp_rpi ) ;
2005-04-18 01:05:31 +04:00
goto out ;
2007-06-18 04:56:38 +04:00
}
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_unreg_rpi ( vport , ndlp ) ;
2007-06-18 04:56:38 +04:00
if ( lpfc_reg_login ( phba , vport - > vpi , irsp - > un . elsreq64 . remoteID ,
( uint8_t * ) sp , mbox , 0 ) = = 0 ) {
2006-03-01 03:25:31 +03:00
switch ( ndlp - > nlp_DID ) {
2005-04-18 01:05:31 +04:00
case NameServer_DID :
2007-04-25 17:52:27 +04:00
mbox - > mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login ;
2005-04-18 01:05:31 +04:00
break ;
case FDMI_DID :
2007-04-25 17:52:27 +04:00
mbox - > mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login ;
2005-04-18 01:05:31 +04:00
break ;
default :
2007-04-25 17:52:27 +04:00
mbox - > mbox_cmpl = lpfc_mbx_cmpl_reg_login ;
2005-04-18 01:05:31 +04:00
}
2007-04-25 17:53:01 +04:00
mbox - > context2 = lpfc_nlp_get ( ndlp ) ;
2007-06-18 04:56:36 +04:00
mbox - > vport = vport ;
2007-10-27 21:37:25 +04:00
if ( lpfc_sli_issue_mbox ( phba , mbox , MBX_NOWAIT )
2005-04-18 01:05:31 +04:00
! = MBX_NOT_FINISHED ) {
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp ,
NLP_STE_REG_LOGIN_ISSUE ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
2008-01-11 09:53:27 +03:00
/* decrement node reference count to the failed mbox
* command
*/
2007-04-25 17:53:01 +04:00
lpfc_nlp_put ( ndlp ) ;
2007-06-18 04:56:38 +04:00
mp = ( struct lpfc_dmabuf * ) mbox - > context1 ;
2006-12-02 21:34:28 +03:00
lpfc_mbuf_free ( phba , mp - > virt , mp - > phys ) ;
kfree ( mp ) ;
2005-04-18 01:05:31 +04:00
mempool_free ( mbox , phba - > mbox_mem_pool ) ;
2007-06-18 04:56:38 +04:00
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0134 PLOGI: cannot issue reg_login "
" Data: x%x x%x x%x x%x \n " ,
ndlp - > nlp_DID , ndlp - > nlp_state ,
ndlp - > nlp_flag , ndlp - > nlp_rpi ) ;
2005-04-18 01:05:31 +04:00
} else {
mempool_free ( mbox , phba - > mbox_mem_pool ) ;
2007-06-18 04:56:38 +04:00
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0135 PLOGI: cannot format reg_login "
" Data: x%x x%x x%x x%x \n " ,
ndlp - > nlp_DID , ndlp - > nlp_state ,
ndlp - > nlp_flag , ndlp - > nlp_rpi ) ;
2005-04-18 01:05:31 +04:00
}
2007-06-18 04:56:38 +04:00
out :
if ( ndlp - > nlp_DID = = NameServer_DID ) {
lpfc_vport_set_state ( vport , FC_VPORT_FAILED ) ;
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_ELS ,
" 0261 Cannot Register NameServer login \n " ) ;
2007-06-18 04:56:38 +04:00
}
2008-01-11 09:52:36 +03:00
spin_lock_irq ( shost - > host_lock ) ;
2007-10-27 21:37:53 +04:00
ndlp - > nlp_flag | = NLP_DEFER_RM ;
2008-01-11 09:52:36 +03:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
return NLP_STE_FREED_NODE ;
2005-04-18 01:05:31 +04:00
}
2008-01-11 09:52:36 +03:00
static uint32_t
lpfc_cmpl_logo_plogi_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
{
return ndlp - > nlp_state ;
}
static uint32_t
lpfc_cmpl_reglogin_plogi_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp , void * arg , uint32_t evt )
{
return ndlp - > nlp_state ;
}
2005-04-18 01:05:31 +04:00
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_rm_plogi_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
if ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) {
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag | = NLP_NODEV_REMOVE ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
return ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
} else {
2006-04-15 19:52:56 +04:00
/* software abort outstanding PLOGI */
2007-06-18 04:56:36 +04:00
lpfc_els_abort ( vport - > phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_plogi_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_hba * phba = vport - > phba ;
2007-06-18 04:56:38 +04:00
/* Don't do anything that will mess up processing of the
* previous RSCN .
*/
if ( vport - > fc_flag & FC_RSCN_DEFERRED )
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
/* software abort outstanding PLOGI */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_PLOGI_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2007-06-18 04:56:38 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_adisc_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * cmdiocb ;
/* software abort outstanding ADISC */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-06-18 04:56:36 +04:00
if ( lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) )
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_ADISC_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_issue_els_plogi ( vport , ndlp - > nlp_DID , 0 ) ;
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_PLOGI_ISSUE ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli_adisc_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_prli_acc ( vport , cmdiocb , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_adisc_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * cmdiocb ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
/* software abort outstanding ADISC */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc_adisc_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
struct lpfc_iocbq * cmdiocb ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prlo_adisc_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
struct lpfc_iocbq * cmdiocb ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
/* Treat like rcv logo */
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_PRLO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_adisc_adisc_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_hba * phba = vport - > phba ;
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * cmdiocb , * rspiocb ;
IOCB_t * irsp ;
ADISC * ap ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
rspiocb = cmdiocb - > context_un . rsp_iocb ;
ap = ( ADISC * ) lpfc_check_elscmpl_iocb ( phba , cmdiocb , rspiocb ) ;
irsp = & rspiocb - > iocb ;
if ( ( irsp - > ulpStatus ) | |
2007-06-18 04:56:38 +04:00
( ! lpfc_check_adisc ( vport , ndlp , & ap - > nodeName , & ap - > portName ) ) ) {
2005-04-18 01:05:31 +04:00
/* 1 sec timeout */
mod_timer ( & ndlp - > nlp_delayfunc , jiffies + HZ ) ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag | = NLP_DELAY_TMO ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_last_elscmd = ELS_CMD_PLOGI ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
memset ( & ndlp - > nlp_nodename , 0 , sizeof ( struct lpfc_name ) ) ;
memset ( & ndlp - > nlp_portname , 0 , sizeof ( struct lpfc_name ) ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_ADISC_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
lpfc_unreg_rpi ( vport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
2006-03-01 03:25:28 +03:00
2005-06-25 18:34:33 +04:00
if ( ndlp - > nlp_type & NLP_FCP_TARGET ) {
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_ADISC_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_MAPPED_NODE ) ;
2005-06-25 18:34:33 +04:00
} else {
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_ADISC_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_UNMAPPED_NODE ) ;
2005-06-25 18:34:33 +04:00
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_rm_adisc_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
if ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) {
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag | = NLP_NODEV_REMOVE ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
return ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
} else {
2006-04-15 19:52:56 +04:00
/* software abort outstanding ADISC */
2007-06-18 04:56:36 +04:00
lpfc_els_abort ( vport - > phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_adisc_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_hba * phba = vport - > phba ;
2007-06-18 04:56:38 +04:00
/* Don't do anything that will mess up processing of the
* previous RSCN .
*/
if ( vport - > fc_flag & FC_RSCN_DEFERRED )
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
/* software abort outstanding ADISC */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_ADISC_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2007-06-18 04:56:38 +04:00
lpfc_disc_set_adisc ( vport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_prli_acc ( vport , cmdiocb , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-04-25 17:52:34 +04:00
LPFC_MBOXQ_t * mb ;
LPFC_MBOXQ_t * nextmb ;
struct lpfc_dmabuf * mp ;
2005-04-18 01:05:31 +04:00
cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-04-25 17:52:34 +04:00
/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
if ( ( mb = phba - > sli . mbox_active ) ) {
if ( ( mb - > mb . mbxCommand = = MBX_REG_LOGIN64 ) & &
( ndlp = = ( struct lpfc_nodelist * ) mb - > context2 ) ) {
2007-06-18 04:56:38 +04:00
lpfc_nlp_put ( ndlp ) ;
2007-04-25 17:52:34 +04:00
mb - > context2 = NULL ;
mb - > mbox_cmpl = lpfc_sli_def_mbox_cmpl ;
}
}
2007-06-18 04:56:36 +04:00
spin_lock_irq ( & phba - > hbalock ) ;
2007-04-25 17:52:34 +04:00
list_for_each_entry_safe ( mb , nextmb , & phba - > sli . mboxq , list ) {
if ( ( mb - > mb . mbxCommand = = MBX_REG_LOGIN64 ) & &
( ndlp = = ( struct lpfc_nodelist * ) mb - > context2 ) ) {
mp = ( struct lpfc_dmabuf * ) ( mb - > context1 ) ;
if ( mp ) {
2007-10-27 21:37:33 +04:00
__lpfc_mbuf_free ( phba , mp - > virt , mp - > phys ) ;
2007-04-25 17:52:34 +04:00
kfree ( mp ) ;
}
2007-06-18 04:56:38 +04:00
lpfc_nlp_put ( ndlp ) ;
2007-04-25 17:52:34 +04:00
list_del ( & mb - > list ) ;
mempool_free ( mb , phba - > mbox_mem_pool ) ;
}
}
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( & phba - > hbalock ) ;
2007-04-25 17:52:34 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prlo_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
struct lpfc_iocbq * cmdiocb ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PRLO , cmdiocb , ndlp , NULL ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_reglogin_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
LPFC_MBOXQ_t * pmb = ( LPFC_MBOXQ_t * ) arg ;
MAILBOX_t * mb = & pmb - > mb ;
uint32_t did = mb - > un . varWords [ 1 ] ;
2005-04-18 01:05:31 +04:00
if ( mb - > mbxStatus ) {
/* RegLogin failed */
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_ERR , LOG_DISCOVERY ,
" 0246 RegLogin failed Data: x%x x%x x%x \n " ,
2007-06-18 04:56:36 +04:00
did , mb - > mbxStatus , vport - > port_state ) ;
2006-07-06 23:49:42 +04:00
/*
* If RegLogin failed due to lack of HBA resources do not
* retry discovery .
*/
if ( mb - > mbxStatus = = MBXERR_RPI_FULL ) {
2007-10-27 21:37:43 +04:00
ndlp - > nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE ;
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2006-07-06 23:49:42 +04:00
return ndlp - > nlp_state ;
}
2007-06-18 04:56:36 +04:00
/* Put ndlp in npr state set plogi timer for 1 sec */
2005-04-18 01:05:31 +04:00
mod_timer ( & ndlp - > nlp_delayfunc , jiffies + HZ * 1 ) ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
ndlp - > nlp_flag | = NLP_DELAY_TMO ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_last_elscmd = ELS_CMD_PLOGI ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_issue_els_logo ( vport , ndlp , 0 ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
ndlp - > nlp_rpi = mb - > un . varWords [ 0 ] ;
/* Only if we are not a fabric nport do we issue PRLI */
if ( ! ( ndlp - > nlp_type & NLP_FABRIC ) ) {
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_PRLI_ISSUE ) ;
lpfc_issue_els_prli ( vport , ndlp , 0 ) ;
2005-04-18 01:05:31 +04:00
} else {
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_UNMAPPED_NODE ) ;
2005-04-18 01:05:31 +04:00
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_rm_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
2005-04-18 01:05:31 +04:00
uint32_t evt )
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
if ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) {
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag | = NLP_NODEV_REMOVE ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
return ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
} else {
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_reglogin_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2007-06-18 04:56:38 +04:00
/* Don't do anything that will mess up processing of the
* previous RSCN .
*/
if ( vport - > fc_flag & FC_RSCN_DEFERRED )
return ndlp - > nlp_state ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2007-06-18 04:56:38 +04:00
lpfc_disc_set_adisc ( vport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
struct lpfc_iocbq * cmdiocb ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_prli_acc ( vport , cmdiocb , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
/* Software abort outstanding PRLI before sending acc */
2007-06-18 04:56:36 +04:00
lpfc_els_abort ( vport - > phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
/* This routine is envoked when we rcv a PRLO request from a nport
* we are logged into . We should send back a PRLO rsp setting the
* appropriate bits .
* NEXT STATE = PRLI_ISSUE
*/
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prlo_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PRLO , cmdiocb , ndlp , NULL ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_prli_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:38 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2005-04-18 01:05:31 +04:00
struct lpfc_iocbq * cmdiocb , * rspiocb ;
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
2005-04-18 01:05:31 +04:00
IOCB_t * irsp ;
PRLI * npr ;
cmdiocb = ( struct lpfc_iocbq * ) arg ;
rspiocb = cmdiocb - > context_un . rsp_iocb ;
npr = ( PRLI * ) lpfc_check_elscmpl_iocb ( phba , cmdiocb , rspiocb ) ;
irsp = & rspiocb - > iocb ;
if ( irsp - > ulpStatus ) {
2007-06-18 04:56:39 +04:00
if ( ( vport - > port_type = = LPFC_NPIV_PORT ) & &
2007-08-02 19:09:59 +04:00
vport - > cfg_restrict_login ) {
2007-06-18 04:56:39 +04:00
goto out ;
}
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_PRLI_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_UNMAPPED_NODE ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
/* Check out PRLI rsp */
ndlp - > nlp_type & = ~ ( NLP_FCP_TARGET | NLP_FCP_INITIATOR ) ;
ndlp - > nlp_fcp_info & = ~ NLP_FCP_2_DEVICE ;
if ( ( npr - > acceptRspCode = = PRLI_REQ_EXECUTED ) & &
( npr - > prliType = = PRLI_FCP_TYPE ) ) {
if ( npr - > initiatorFunc )
ndlp - > nlp_type | = NLP_FCP_INITIATOR ;
if ( npr - > targetFunc )
ndlp - > nlp_type | = NLP_FCP_TARGET ;
if ( npr - > Retry )
ndlp - > nlp_fcp_info | = NLP_FCP_2_DEVICE ;
}
2007-06-18 04:56:38 +04:00
if ( ! ( ndlp - > nlp_type & NLP_FCP_TARGET ) & &
( vport - > port_type = = LPFC_NPIV_PORT ) & &
2007-08-02 19:09:59 +04:00
vport - > cfg_restrict_login ) {
2007-06-18 04:56:39 +04:00
out :
2007-06-18 04:56:38 +04:00
spin_lock_irq ( shost - > host_lock ) ;
ndlp - > nlp_flag | = NLP_TARGET_REMOVE ;
spin_unlock_irq ( shost - > host_lock ) ;
lpfc_issue_els_logo ( vport , ndlp , 0 ) ;
ndlp - > nlp_prev_state = NLP_STE_PRLI_ISSUE ;
2007-10-27 21:37:43 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
2007-06-18 04:56:38 +04:00
return ndlp - > nlp_state ;
}
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_PRLI_ISSUE ;
2007-06-18 04:56:38 +04:00
if ( ndlp - > nlp_type & NLP_FCP_TARGET )
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_MAPPED_NODE ) ;
else
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_UNMAPPED_NODE ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
/*! lpfc_device_rm_prli_issue
2007-06-18 04:56:38 +04:00
*
* \ pre
* \ post
* \ param phba
* \ param ndlp
* \ param arg
* \ param evt
* \ return uint32_t
*
* \ b Description :
* This routine is envoked when we a request to remove a nport we are in the
* process of PRLIing . We should software abort outstanding prli , unreg
* login , send a logout . We will change node state to UNUSED_NODE , put it
* on plogi list so it can be freed when LOGO completes .
*
*/
2005-04-18 01:05:31 +04:00
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_rm_prli_issue ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
if ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) {
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag | = NLP_NODEV_REMOVE ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
return ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
} else {
2006-04-15 19:52:56 +04:00
/* software abort outstanding PLOGI */
2007-06-18 04:56:36 +04:00
lpfc_els_abort ( vport - > phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2005-04-18 01:05:31 +04:00
}
/*! lpfc_device_recov_prli_issue
2007-06-18 04:56:38 +04:00
*
* \ pre
* \ post
* \ param phba
* \ param ndlp
* \ param arg
* \ param evt
* \ return uint32_t
*
* \ b Description :
* The routine is envoked when the state of a device is unknown , like
* during a link down . We should remove the nodelist entry from the
* unmapped list , issue a UNREG_LOGIN , do a software abort of the
* outstanding PRLI command , then free the node entry .
*/
2005-04-18 01:05:31 +04:00
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_prli_issue ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_hba * phba = vport - > phba ;
2007-06-18 04:56:38 +04:00
/* Don't do anything that will mess up processing of the
* previous RSCN .
*/
if ( vport - > fc_flag & FC_RSCN_DEFERRED )
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
/* software abort outstanding PRLI */
2007-04-25 17:51:38 +04:00
lpfc_els_abort ( phba , ndlp ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_PRLI_ISSUE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2007-06-18 04:56:38 +04:00
lpfc_disc_set_adisc ( vport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_unmap_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli_unmap_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli ( vport , ndlp , cmdiocb ) ;
lpfc_els_rsp_prli_acc ( vport , cmdiocb , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_unmap_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc_unmap_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prlo_unmap_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_PRLO , cmdiocb , ndlp , NULL ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_unmap_node ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_UNMAPPED_NODE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
lpfc_disc_set_adisc ( vport , ndlp ) ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_mapped_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli_mapped_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_els_rsp_prli_acc ( vport , cmdiocb , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_mapped_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc_mapped_node ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( vport , ndlp , cmdiocb ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prlo_mapped_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_hba * phba = vport - > phba ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
/* flush the target */
2007-08-02 19:10:31 +04:00
lpfc_sli_abort_iocb ( vport , & phba - > sli . ring [ phba - > sli . fcp_ring ] ,
ndlp - > nlp_sid , 0 , LPFC_CTX_TGT ) ;
2005-04-18 01:05:31 +04:00
/* Treat like rcv logo */
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_PRLO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_mapped_node ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg ,
uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_MAPPED_NODE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_NPR_NODE ) ;
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
lpfc_disc_set_adisc ( vport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_plogi_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
/* Ignore PLOGI if we have an outstanding LOGO */
2007-06-18 04:56:39 +04:00
if ( ndlp - > nlp_flag & ( NLP_LOGO_SND | NLP_LOGO_ACC ) ) {
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
2007-06-18 04:56:36 +04:00
if ( lpfc_rcv_plogi ( vport , ndlp , cmdiocb ) ) {
spin_lock_irq ( shost - > host_lock ) ;
2006-03-07 23:04:01 +03:00
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
/* send PLOGI immediately, move to PLOGI issue state */
if ( ! ( ndlp - > nlp_flag & NLP_DELAY_TMO ) ) {
2006-03-07 23:02:37 +03:00
ndlp - > nlp_prev_state = NLP_STE_NPR_NODE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_PLOGI_ISSUE ) ;
lpfc_issue_els_plogi ( vport , ndlp - > nlp_DID , 0 ) ;
2005-04-18 01:05:31 +04:00
}
2006-03-07 23:02:37 +03:00
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prli_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
struct ls_rjt stat ;
2005-04-18 01:05:31 +04:00
memset ( & stat , 0 , sizeof ( struct ls_rjt ) ) ;
stat . un . b . lsRjtRsnCode = LSRJT_UNABLE_TPC ;
stat . un . b . lsRjtRsnCodeExp = LSEXP_NOTHING_MORE ;
2007-06-18 04:56:39 +04:00
lpfc_els_rsp_reject ( vport , stat . un . lsRjtError , cmdiocb , ndlp , NULL ) ;
2005-04-18 01:05:31 +04:00
if ( ! ( ndlp - > nlp_flag & NLP_DELAY_TMO ) ) {
if ( ndlp - > nlp_flag & NLP_NPR_ADISC ) {
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_NPR_NODE ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_ADISC_ISSUE ) ;
lpfc_issue_els_adisc ( vport , ndlp , 0 ) ;
2005-04-18 01:05:31 +04:00
} else {
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_NPR_NODE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_PLOGI_ISSUE ) ;
lpfc_issue_els_plogi ( vport , ndlp - > nlp_DID , 0 ) ;
2005-04-18 01:05:31 +04:00
}
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_logo ( vport , ndlp , cmdiocb , ELS_CMD_LOGO ) ;
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
lpfc_rcv_padisc ( vport , ndlp , cmdiocb ) ;
2005-04-18 01:05:31 +04:00
2006-08-17 19:57:58 +04:00
/*
* Do not start discovery if discovery is about to start
* or discovery in progress for this node . Starting discovery
* here will affect the counting of discovery threads .
*/
2006-12-02 21:33:57 +03:00
if ( ! ( ndlp - > nlp_flag & NLP_DELAY_TMO ) & &
2007-06-18 04:56:38 +04:00
! ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) ) {
2005-04-18 01:05:31 +04:00
if ( ndlp - > nlp_flag & NLP_NPR_ADISC ) {
2007-06-18 04:56:38 +04:00
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_NPR_NODE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_ADISC_ISSUE ) ;
lpfc_issue_els_adisc ( vport , ndlp , 0 ) ;
2005-04-18 01:05:31 +04:00
} else {
2006-03-01 03:25:28 +03:00
ndlp - > nlp_prev_state = NLP_STE_NPR_NODE ;
2007-06-18 04:56:36 +04:00
lpfc_nlp_set_state ( vport , ndlp , NLP_STE_PLOGI_ISSUE ) ;
lpfc_issue_els_plogi ( vport , ndlp - > nlp_DID , 0 ) ;
2005-04-18 01:05:31 +04:00
}
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_rcv_prlo_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
struct lpfc_iocbq * cmdiocb = ( struct lpfc_iocbq * ) arg ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
ndlp - > nlp_flag | = NLP_LOGO_ACC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
2007-08-02 19:10:31 +04:00
lpfc_els_rsp_acc ( vport , ELS_CMD_ACC , cmdiocb , ndlp , NULL ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:36 +04:00
if ( ( ndlp - > nlp_flag & NLP_DELAY_TMO ) = = 0 ) {
2006-03-01 03:25:23 +03:00
mod_timer ( & ndlp - > nlp_delayfunc , jiffies + HZ * 1 ) ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
ndlp - > nlp_flag | = NLP_DELAY_TMO ;
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:28 +03:00
ndlp - > nlp_last_elscmd = ELS_CMD_PLOGI ;
2006-03-01 03:25:23 +03:00
} else {
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:23 +03:00
ndlp - > nlp_flag & = ~ NLP_NPR_ADISC ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2005-04-18 01:05:31 +04:00
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
}
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_plogi_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2006-03-01 03:25:23 +03:00
{
struct lpfc_iocbq * cmdiocb , * rspiocb ;
2006-04-15 19:52:56 +04:00
IOCB_t * irsp ;
2006-03-01 03:25:23 +03:00
cmdiocb = ( struct lpfc_iocbq * ) arg ;
rspiocb = cmdiocb - > context_un . rsp_iocb ;
2006-04-15 19:52:56 +04:00
irsp = & rspiocb - > iocb ;
if ( irsp - > ulpStatus ) {
2007-10-27 21:37:53 +04:00
ndlp - > nlp_flag | = NLP_DEFER_RM ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_prli_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2006-03-01 03:25:23 +03:00
{
struct lpfc_iocbq * cmdiocb , * rspiocb ;
2006-04-15 19:52:56 +04:00
IOCB_t * irsp ;
2006-03-01 03:25:23 +03:00
cmdiocb = ( struct lpfc_iocbq * ) arg ;
rspiocb = cmdiocb - > context_un . rsp_iocb ;
2006-04-15 19:52:56 +04:00
irsp = & rspiocb - > iocb ;
if ( irsp - > ulpStatus & & ( ndlp - > nlp_flag & NLP_NODEV_REMOVE ) ) {
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_logo_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
lpfc_unreg_rpi ( vport , ndlp ) ;
2005-04-18 01:05:31 +04:00
/* This routine does nothing, just return the current state */
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_adisc_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2006-03-01 03:25:23 +03:00
{
struct lpfc_iocbq * cmdiocb , * rspiocb ;
2006-04-15 19:52:56 +04:00
IOCB_t * irsp ;
2006-03-01 03:25:23 +03:00
cmdiocb = ( struct lpfc_iocbq * ) arg ;
rspiocb = cmdiocb - > context_un . rsp_iocb ;
2006-04-15 19:52:56 +04:00
irsp = & rspiocb - > iocb ;
if ( irsp - > ulpStatus & & ( ndlp - > nlp_flag & NLP_NODEV_REMOVE ) ) {
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_cmpl_reglogin_npr_node ( struct lpfc_vport * vport ,
struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
LPFC_MBOXQ_t * pmb = ( LPFC_MBOXQ_t * ) arg ;
MAILBOX_t * mb = & pmb - > mb ;
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
if ( ! mb - > mbxStatus )
ndlp - > nlp_rpi = mb - > un . varWords [ 0 ] ;
2006-04-15 19:52:56 +04:00
else {
if ( ndlp - > nlp_flag & NLP_NODEV_REMOVE ) {
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-04-15 19:52:56 +04:00
return NLP_STE_FREED_NODE ;
}
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_rm_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2006-04-15 19:52:56 +04:00
if ( ndlp - > nlp_flag & NLP_NPR_2B_DISC ) {
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag | = NLP_NODEV_REMOVE ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
return ndlp - > nlp_state ;
}
2007-06-18 04:56:36 +04:00
lpfc_drop_node ( vport , ndlp ) ;
2006-03-01 03:25:23 +03:00
return NLP_STE_FREED_NODE ;
2005-04-18 01:05:31 +04:00
}
static uint32_t
2007-06-18 04:56:36 +04:00
lpfc_device_recov_npr_node ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
2007-06-18 04:56:36 +04:00
struct Scsi_Host * shost = lpfc_shost_from_vport ( vport ) ;
2007-06-18 04:56:38 +04:00
/* Don't do anything that will mess up processing of the
* previous RSCN .
*/
if ( vport - > fc_flag & FC_RSCN_DEFERRED )
return ndlp - > nlp_state ;
2007-06-18 04:56:36 +04:00
spin_lock_irq ( shost - > host_lock ) ;
2006-04-15 19:52:56 +04:00
ndlp - > nlp_flag & = ~ ( NLP_NODEV_REMOVE | NLP_NPR_2B_DISC ) ;
2007-06-18 04:56:36 +04:00
spin_unlock_irq ( shost - > host_lock ) ;
2006-03-01 03:25:16 +03:00
if ( ndlp - > nlp_flag & NLP_DELAY_TMO ) {
2007-06-18 04:56:36 +04:00
lpfc_cancel_retry_delay_tmo ( vport , ndlp ) ;
2006-03-01 03:25:16 +03:00
}
2006-03-01 03:25:23 +03:00
return ndlp - > nlp_state ;
2005-04-18 01:05:31 +04:00
}
/* This next section defines the NPort Discovery State Machine */
/* There are 4 different double linked lists nodelist entries can reside on.
* The plogi list and adisc list are used when Link Up discovery or RSCN
* processing is needed . Each list holds the nodes that we will send PLOGI
* or ADISC on . These lists will keep track of what nodes will be effected
* by an RSCN , or a Link Up ( Typically , all nodes are effected on Link Up ) .
* The unmapped_list will contain all nodes that we have successfully logged
* into at the Fibre Channel level . The mapped_list will contain all nodes
* that are mapped FCP targets .
*/
/*
* The bind list is a list of undiscovered ( potentially non - existent ) nodes
* that we have saved binding information on . This information is used when
* nodes transition from the unmapped to the mapped list .
*/
/* For UNUSED_NODE state, the node has just been allocated .
* For PLOGI_ISSUE and REG_LOGIN_ISSUE , the node is on
* the PLOGI list . For REG_LOGIN_COMPL , the node is taken off the PLOGI list
* and put on the unmapped list . For ADISC processing , the node is taken off
* the ADISC list and placed on either the mapped or unmapped list ( depending
* on its previous state ) . Once on the unmapped list , a PRLI is issued and the
* state changed to PRLI_ISSUE . When the PRLI completion occurs , the state is
* changed to UNMAPPED_NODE . If the completion indicates a mapped
* node , the node is taken off the unmapped list . The binding list is checked
* for a valid binding , or a binding is automatically assigned . If binding
* assignment is unsuccessful , the node is left on the unmapped list . If
* binding assignment is successful , the associated binding list entry ( if
* any ) is removed , and the node is placed on the mapped list .
*/
/*
* For a Link Down , all nodes on the ADISC , PLOGI , unmapped or mapped
2006-08-19 01:47:08 +04:00
* lists will receive a DEVICE_RECOVERY event . If the linkdown or devloss timers
2005-04-18 01:05:31 +04:00
* expire , all effected nodes will receive a DEVICE_RM event .
*/
/*
* For a Link Up or RSCN , all nodes will move from the mapped / unmapped lists
* to either the ADISC or PLOGI list . After a Nameserver query or ALPA loopmap
* check , additional nodes may be added or removed ( via DEVICE_RM ) to / from
* the PLOGI or ADISC lists . Once the PLOGI and ADISC lists are populated ,
* we will first process the ADISC list . 32 entries are processed initially and
* ADISC is initited for each one . Completions / Events for each node are
* funnelled thru the state machine . As each node finishes ADISC processing , it
* starts ADISC for any nodes waiting for ADISC processing . If no nodes are
* waiting , and the ADISC list count is identically 0 , then we are done . For
* Link Up discovery , since all nodes on the PLOGI list are UNREG_LOGIN ' ed , we
* can issue a CLEAR_LA and reenable Link Events . Next we will process the PLOGI
* list . 32 entries are processed initially and PLOGI is initited for each one .
* Completions / Events for each node are funnelled thru the state machine . As
* each node finishes PLOGI processing , it starts PLOGI for any nodes waiting
* for PLOGI processing . If no nodes are waiting , and the PLOGI list count is
* indentically 0 , then we are done . We have now completed discovery / RSCN
* handling . Upon completion , ALL nodes should be on either the mapped or
* unmapped lists .
*/
static uint32_t ( * lpfc_disc_action [ NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT ] )
2007-06-18 04:56:36 +04:00
( struct lpfc_vport * , struct lpfc_nodelist * , void * , uint32_t ) = {
2005-04-18 01:05:31 +04:00
/* Action routine Event Current State */
lpfc_rcv_plogi_unused_node , /* RCV_PLOGI UNUSED_NODE */
lpfc_rcv_els_unused_node , /* RCV_PRLI */
lpfc_rcv_logo_unused_node , /* RCV_LOGO */
lpfc_rcv_els_unused_node , /* RCV_ADISC */
lpfc_rcv_els_unused_node , /* RCV_PDISC */
lpfc_rcv_els_unused_node , /* RCV_PRLO */
lpfc_disc_illegal , /* CMPL_PLOGI */
lpfc_disc_illegal , /* CMPL_PRLI */
lpfc_cmpl_logo_unused_node , /* CMPL_LOGO */
lpfc_disc_illegal , /* CMPL_ADISC */
lpfc_disc_illegal , /* CMPL_REG_LOGIN */
lpfc_device_rm_unused_node , /* DEVICE_RM */
lpfc_disc_illegal , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_plogi_issue , /* RCV_PLOGI PLOGI_ISSUE */
2007-06-18 04:56:38 +04:00
lpfc_rcv_prli_plogi_issue , /* RCV_PRLI */
2006-03-01 03:25:23 +03:00
lpfc_rcv_logo_plogi_issue , /* RCV_LOGO */
2005-04-18 01:05:31 +04:00
lpfc_rcv_els_plogi_issue , /* RCV_ADISC */
lpfc_rcv_els_plogi_issue , /* RCV_PDISC */
lpfc_rcv_els_plogi_issue , /* RCV_PRLO */
lpfc_cmpl_plogi_plogi_issue , /* CMPL_PLOGI */
lpfc_disc_illegal , /* CMPL_PRLI */
2008-01-11 09:52:36 +03:00
lpfc_cmpl_logo_plogi_issue , /* CMPL_LOGO */
2005-04-18 01:05:31 +04:00
lpfc_disc_illegal , /* CMPL_ADISC */
2008-01-11 09:52:36 +03:00
lpfc_cmpl_reglogin_plogi_issue , /* CMPL_REG_LOGIN */
2005-04-18 01:05:31 +04:00
lpfc_device_rm_plogi_issue , /* DEVICE_RM */
lpfc_device_recov_plogi_issue , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_adisc_issue , /* RCV_PLOGI ADISC_ISSUE */
lpfc_rcv_prli_adisc_issue , /* RCV_PRLI */
lpfc_rcv_logo_adisc_issue , /* RCV_LOGO */
lpfc_rcv_padisc_adisc_issue , /* RCV_ADISC */
lpfc_rcv_padisc_adisc_issue , /* RCV_PDISC */
lpfc_rcv_prlo_adisc_issue , /* RCV_PRLO */
lpfc_disc_illegal , /* CMPL_PLOGI */
lpfc_disc_illegal , /* CMPL_PRLI */
lpfc_disc_illegal , /* CMPL_LOGO */
lpfc_cmpl_adisc_adisc_issue , /* CMPL_ADISC */
lpfc_disc_illegal , /* CMPL_REG_LOGIN */
lpfc_device_rm_adisc_issue , /* DEVICE_RM */
lpfc_device_recov_adisc_issue , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_reglogin_issue , /* RCV_PLOGI REG_LOGIN_ISSUE */
lpfc_rcv_prli_reglogin_issue , /* RCV_PLOGI */
lpfc_rcv_logo_reglogin_issue , /* RCV_LOGO */
lpfc_rcv_padisc_reglogin_issue , /* RCV_ADISC */
lpfc_rcv_padisc_reglogin_issue , /* RCV_PDISC */
lpfc_rcv_prlo_reglogin_issue , /* RCV_PRLO */
2007-10-27 21:37:43 +04:00
lpfc_cmpl_plogi_illegal , /* CMPL_PLOGI */
2005-04-18 01:05:31 +04:00
lpfc_disc_illegal , /* CMPL_PRLI */
lpfc_disc_illegal , /* CMPL_LOGO */
lpfc_disc_illegal , /* CMPL_ADISC */
lpfc_cmpl_reglogin_reglogin_issue , /* CMPL_REG_LOGIN */
lpfc_device_rm_reglogin_issue , /* DEVICE_RM */
lpfc_device_recov_reglogin_issue , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_prli_issue , /* RCV_PLOGI PRLI_ISSUE */
lpfc_rcv_prli_prli_issue , /* RCV_PRLI */
lpfc_rcv_logo_prli_issue , /* RCV_LOGO */
lpfc_rcv_padisc_prli_issue , /* RCV_ADISC */
lpfc_rcv_padisc_prli_issue , /* RCV_PDISC */
lpfc_rcv_prlo_prli_issue , /* RCV_PRLO */
2007-10-27 21:37:43 +04:00
lpfc_cmpl_plogi_illegal , /* CMPL_PLOGI */
2005-04-18 01:05:31 +04:00
lpfc_cmpl_prli_prli_issue , /* CMPL_PRLI */
lpfc_disc_illegal , /* CMPL_LOGO */
lpfc_disc_illegal , /* CMPL_ADISC */
lpfc_disc_illegal , /* CMPL_REG_LOGIN */
lpfc_device_rm_prli_issue , /* DEVICE_RM */
lpfc_device_recov_prli_issue , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_unmap_node , /* RCV_PLOGI UNMAPPED_NODE */
lpfc_rcv_prli_unmap_node , /* RCV_PRLI */
lpfc_rcv_logo_unmap_node , /* RCV_LOGO */
lpfc_rcv_padisc_unmap_node , /* RCV_ADISC */
lpfc_rcv_padisc_unmap_node , /* RCV_PDISC */
lpfc_rcv_prlo_unmap_node , /* RCV_PRLO */
lpfc_disc_illegal , /* CMPL_PLOGI */
lpfc_disc_illegal , /* CMPL_PRLI */
lpfc_disc_illegal , /* CMPL_LOGO */
lpfc_disc_illegal , /* CMPL_ADISC */
lpfc_disc_illegal , /* CMPL_REG_LOGIN */
lpfc_disc_illegal , /* DEVICE_RM */
lpfc_device_recov_unmap_node , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_mapped_node , /* RCV_PLOGI MAPPED_NODE */
lpfc_rcv_prli_mapped_node , /* RCV_PRLI */
lpfc_rcv_logo_mapped_node , /* RCV_LOGO */
lpfc_rcv_padisc_mapped_node , /* RCV_ADISC */
lpfc_rcv_padisc_mapped_node , /* RCV_PDISC */
lpfc_rcv_prlo_mapped_node , /* RCV_PRLO */
lpfc_disc_illegal , /* CMPL_PLOGI */
lpfc_disc_illegal , /* CMPL_PRLI */
lpfc_disc_illegal , /* CMPL_LOGO */
lpfc_disc_illegal , /* CMPL_ADISC */
lpfc_disc_illegal , /* CMPL_REG_LOGIN */
lpfc_disc_illegal , /* DEVICE_RM */
lpfc_device_recov_mapped_node , /* DEVICE_RECOVERY */
lpfc_rcv_plogi_npr_node , /* RCV_PLOGI NPR_NODE */
lpfc_rcv_prli_npr_node , /* RCV_PRLI */
lpfc_rcv_logo_npr_node , /* RCV_LOGO */
lpfc_rcv_padisc_npr_node , /* RCV_ADISC */
lpfc_rcv_padisc_npr_node , /* RCV_PDISC */
lpfc_rcv_prlo_npr_node , /* RCV_PRLO */
2006-03-01 03:25:23 +03:00
lpfc_cmpl_plogi_npr_node , /* CMPL_PLOGI */
lpfc_cmpl_prli_npr_node , /* CMPL_PRLI */
2005-04-18 01:05:31 +04:00
lpfc_cmpl_logo_npr_node , /* CMPL_LOGO */
2006-03-01 03:25:23 +03:00
lpfc_cmpl_adisc_npr_node , /* CMPL_ADISC */
2005-04-18 01:05:31 +04:00
lpfc_cmpl_reglogin_npr_node , /* CMPL_REG_LOGIN */
lpfc_device_rm_npr_node , /* DEVICE_RM */
lpfc_device_recov_npr_node , /* DEVICE_RECOVERY */
} ;
int
2007-06-18 04:56:36 +04:00
lpfc_disc_state_machine ( struct lpfc_vport * vport , struct lpfc_nodelist * ndlp ,
void * arg , uint32_t evt )
2005-04-18 01:05:31 +04:00
{
uint32_t cur_state , rc ;
2007-06-18 04:56:36 +04:00
uint32_t ( * func ) ( struct lpfc_vport * , struct lpfc_nodelist * , void * ,
2005-04-18 01:05:31 +04:00
uint32_t ) ;
2008-02-09 02:49:26 +03:00
uint32_t got_ndlp = 0 ;
if ( lpfc_nlp_get ( ndlp ) )
got_ndlp = 1 ;
2005-04-18 01:05:31 +04:00
cur_state = ndlp - > nlp_state ;
/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
2007-08-02 19:10:09 +04:00
lpfc_printf_vlog ( vport , KERN_INFO , LOG_DISCOVERY ,
" 0211 DSM in event x%x on NPort x%x in "
" state %d Data: x%x \n " ,
evt , ndlp - > nlp_DID , cur_state , ndlp - > nlp_flag ) ;
2005-04-18 01:05:31 +04:00
2007-06-18 04:56:39 +04:00
lpfc_debugfs_disc_trc ( vport , LPFC_DISC_TRC_DSM ,
" DSM in: evt:%d ste:%d did:x%x " ,
evt , cur_state , ndlp - > nlp_DID ) ;
2005-04-18 01:05:31 +04:00
func = lpfc_disc_action [ ( cur_state * NLP_EVT_MAX_EVENT ) + evt ] ;
2007-06-18 04:56:36 +04:00
rc = ( func ) ( vport , ndlp , arg , evt ) ;
2005-04-18 01:05:31 +04:00
/* DSM out state <rc> on NPort <nlp_DID> */
2008-02-09 02:49:26 +03:00
if ( got_ndlp ) {
lpfc_printf_vlog ( vport , KERN_INFO , LOG_DISCOVERY ,
2007-08-02 19:10:09 +04:00
" 0212 DSM out state %d on NPort x%x Data: x%x \n " ,
rc , ndlp - > nlp_DID , ndlp - > nlp_flag ) ;
2005-04-18 01:05:31 +04:00
2008-02-09 02:49:26 +03:00
lpfc_debugfs_disc_trc ( vport , LPFC_DISC_TRC_DSM ,
" DSM out: ste:%d did:x%x flg:x%x " ,
rc , ndlp - > nlp_DID , ndlp - > nlp_flag ) ;
/* Decrement the ndlp reference count held for this function */
lpfc_nlp_put ( ndlp ) ;
} else {
lpfc_printf_vlog ( vport , KERN_INFO , LOG_DISCOVERY ,
" 0212 DSM out state %d on NPort free \n " , rc ) ;
2007-06-18 04:56:39 +04:00
2008-02-09 02:49:26 +03:00
lpfc_debugfs_disc_trc ( vport , LPFC_DISC_TRC_DSM ,
" DSM out: ste:%d did:x%x flg:x%x " ,
rc , 0 , 0 ) ;
}
2005-04-18 01:05:31 +04:00
2006-03-01 03:25:23 +03:00
return rc ;
2005-04-18 01:05:31 +04:00
}