[SCSI] lpfc 8.3.28: Add support for ABTS failure handling

Add support for ABTS failure handling:

- Add asynchronous ABTS notification event feature to driver (CR 124578)
- Change driver message 3092 and 3116 to KERN_WARNING (CR 124768)
- Alter the SCR ELS command to use the temporary RPI and the
  Destination DID for SLI4-FC (CR 126070)

Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
James Smart 2011-12-13 13:21:57 -05:00 committed by James Bottomley
parent ff78d8f97c
commit cb69f7decc
7 changed files with 263 additions and 93 deletions

View file

@ -106,7 +106,7 @@ void lpfc_cleanup(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long);
struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
void lpfc_worker_wake_up(struct lpfc_hba *);
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
int lpfc_do_work(void *);
@ -455,3 +455,5 @@ int lpfc_sli4_queue_create(struct lpfc_hba *);
void lpfc_sli4_queue_destroy(struct lpfc_hba *);
int lpfc_sli4_read_config(struct lpfc_hba *phba);
int lpfc_scsi_buf_update(struct lpfc_hba *phba);
void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *,
struct sli4_wcqe_xri_aborted *);

View file

@ -6595,56 +6595,6 @@ dropit:
phba->fc_stat.elsRcvDrop++;
}
/**
* lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier
* @phba: pointer to lpfc hba data structure.
* @vpi: host virtual N_Port identifier.
*
* This routine finds a vport on a HBA (referred by @phba) through a
* @vpi. The function walks the HBA's vport list and returns the address
* of the vport with the matching @vpi.
*
* Return code
* NULL - No vport with the matching @vpi found
* Otherwise - Address to the vport with the matching @vpi.
**/
struct lpfc_vport *
lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
{
struct lpfc_vport *vport;
unsigned long flags;
int i = 0;
/* The physical ports are always vpi 0 - translate is unnecessary. */
if (vpi > 0) {
/*
* Translate the physical vpi to the logical vpi. The
* vport stores the logical vpi.
*/
for (i = 0; i < phba->max_vpi; i++) {
if (vpi == phba->vpi_ids[i])
break;
}
if (i >= phba->max_vpi) {
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
"2936 Could not find Vport mapped "
"to vpi %d\n", vpi);
return NULL;
}
}
spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport->vpi == i) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return vport;
}
}
spin_unlock_irqrestore(&phba->hbalock, flags);
return NULL;
}
/**
* lpfc_els_unsol_event - Process an unsolicited event from an els sli ring
* @phba: pointer to lpfc hba data structure.

View file

@ -5352,6 +5352,73 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn)
return ndlp;
}
/*
* This routine looks up the ndlp lists for the given RPI. If the rpi
* is found, the routine returns the node element list pointer else
* return NULL.
*/
struct lpfc_nodelist *
lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
spin_lock_irq(shost->host_lock);
ndlp = __lpfc_findnode_rpi(vport, rpi);
spin_unlock_irq(shost->host_lock);
return ndlp;
}
/**
* lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier
* @phba: pointer to lpfc hba data structure.
* @vpi: the physical host virtual N_Port identifier.
*
* This routine finds a vport on a HBA (referred by @phba) through a
* @vpi. The function walks the HBA's vport list and returns the address
* of the vport with the matching @vpi.
*
* Return code
* NULL - No vport with the matching @vpi found
* Otherwise - Address to the vport with the matching @vpi.
**/
struct lpfc_vport *
lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
{
struct lpfc_vport *vport;
unsigned long flags;
int i = 0;
/* The physical ports are always vpi 0 - translate is unnecessary. */
if (vpi > 0) {
/*
* Translate the physical vpi to the logical vpi. The
* vport stores the logical vpi.
*/
for (i = 0; i < phba->max_vpi; i++) {
if (vpi == phba->vpi_ids[i])
break;
}
if (i >= phba->max_vpi) {
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
"2936 Could not find Vport mapped "
"to vpi %d\n", vpi);
return NULL;
}
}
spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport->vpi == i) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return vport;
}
}
spin_unlock_irqrestore(&phba->hbalock, flags);
return NULL;
}
void
lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t did)

View file

@ -2819,7 +2819,8 @@ typedef struct {
#ifdef __BIG_ENDIAN_BITFIELD
uint32_t rsvd1 : 19; /* Reserved */
uint32_t cdss : 1; /* Configure Data Security SLI */
uint32_t rsvd2 : 3; /* Reserved */
uint32_t casabt : 1; /* Configure async abts status notice */
uint32_t rsvd2 : 2; /* Reserved */
uint32_t cbg : 1; /* Configure BlockGuard */
uint32_t cmv : 1; /* Configure Max VPIs */
uint32_t ccrp : 1; /* Config Command Ring Polling */
@ -2839,14 +2840,16 @@ typedef struct {
uint32_t ccrp : 1; /* Config Command Ring Polling */
uint32_t cmv : 1; /* Configure Max VPIs */
uint32_t cbg : 1; /* Configure BlockGuard */
uint32_t rsvd2 : 3; /* Reserved */
uint32_t rsvd2 : 2; /* Reserved */
uint32_t casabt : 1; /* Configure async abts status notice */
uint32_t cdss : 1; /* Configure Data Security SLI */
uint32_t rsvd1 : 19; /* Reserved */
#endif
#ifdef __BIG_ENDIAN_BITFIELD
uint32_t rsvd3 : 19; /* Reserved */
uint32_t gdss : 1; /* Configure Data Security SLI */
uint32_t rsvd4 : 3; /* Reserved */
uint32_t gasabt : 1; /* Grant async abts status notice */
uint32_t rsvd4 : 2; /* Reserved */
uint32_t gbg : 1; /* Grant BlockGuard */
uint32_t gmv : 1; /* Grant Max VPIs */
uint32_t gcrp : 1; /* Grant Command Ring Polling */
@ -2866,7 +2869,8 @@ typedef struct {
uint32_t gcrp : 1; /* Grant Command Ring Polling */
uint32_t gmv : 1; /* Grant Max VPIs */
uint32_t gbg : 1; /* Grant BlockGuard */
uint32_t rsvd4 : 3; /* Reserved */
uint32_t rsvd4 : 2; /* Reserved */
uint32_t gasabt : 1; /* Grant async abts status notice */
uint32_t gdss : 1; /* Configure Data Security SLI */
uint32_t rsvd3 : 19; /* Reserved */
#endif
@ -3465,6 +3469,7 @@ typedef struct {
} ASYNCSTAT_FIELDS;
#define ASYNC_TEMP_WARN 0x100
#define ASYNC_TEMP_SAFE 0x101
#define ASYNC_STATUS_CN 0x102
/* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
or CMD_IOCB_RCV_SEQ64_CX (0xB5) */

View file

@ -1293,6 +1293,10 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
phba->sli_rev = LPFC_SLI_REV2;
mb->un.varCfgPort.sli_mode = phba->sli_rev;
/* If this is an SLI3 port, configure async status notification. */
if (phba->sli_rev == LPFC_SLI_REV3)
mb->un.varCfgPort.casabt = 1;
/* Now setup pcb */
phba->pcb->type = TYPE_NATIVE_SLI2;
phba->pcb->feature = FEATURE_INITIAL_SLI2;

View file

@ -681,8 +681,10 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
if (ndlp)
if (ndlp) {
lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
lpfc_sli4_abts_err_handler(phba, ndlp, axri);
}
lpfc_release_scsi_buf_s4(phba, psb);
if (rrq_empty)
lpfc_worker_wake_up(phba);

View file

@ -4339,6 +4339,11 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
spin_unlock_irq(&phba->hbalock);
done = 1;
if ((pmb->u.mb.un.varCfgPort.casabt == 1) &&
(pmb->u.mb.un.varCfgPort.gasabt == 0))
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"3110 Port did not grant ASABT\n");
}
}
if (!done) {
@ -7704,6 +7709,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
iocbq->context2)->virt);
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
*pcmd == ELS_CMD_SCR ||
*pcmd == ELS_CMD_PLOGI)) {
bf_set(els_req64_sp, &wqe->els_req, 1);
bf_set(els_req64_sid, &wqe->els_req,
@ -8213,6 +8219,137 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
return 0;
}
/* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS.
* @vport: pointer to virtual port object.
* @ndlp: nodelist pointer for the impacted rport.
*
* The driver calls this routine in response to a XRI ABORT CQE
* event from the port. In this event, the driver is required to
* recover its login to the rport even though its login may be valid
* from the driver's perspective. The failed ABTS notice from the
* port indicates the rport is not responding.
*/
static void
lpfc_sli_abts_recover_port(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp)
{
struct Scsi_Host *shost;
struct lpfc_hba *phba;
unsigned long flags = 0;
shost = lpfc_shost_from_vport(vport);
phba = vport->phba;
if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) {
lpfc_printf_log(phba, KERN_INFO,
LOG_SLI, "3093 No rport recovery needed. "
"rport in state 0x%x\n",
ndlp->nlp_state);
return;
}
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3094 Start rport recovery on shost id 0x%x "
"fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x "
"flags 0x%x\n",
shost->host_no, ndlp->nlp_DID,
vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state,
ndlp->nlp_flag);
/*
* The rport is not responding. Don't attempt ADISC recovery.
* Remove the FCP-2 flag to force a PLOGI.
*/
spin_lock_irqsave(shost->host_lock, flags);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
spin_unlock_irqrestore(shost->host_lock, flags);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
lpfc_cancel_retry_delay_tmo(vport, ndlp);
spin_lock_irqsave(shost->host_lock, flags);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
spin_unlock_irqrestore(shost->host_lock, flags);
lpfc_disc_start(vport);
}
/* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port.
* @phba: Pointer to HBA context object.
* @iocbq: Pointer to iocb object.
*
* The async_event handler calls this routine when it receives
* an ASYNC_STATUS_CN event from the port. The port generates
* this event when an Abort Sequence request to an rport fails
* twice in succession. The abort could be originated by the
* driver or by the port. The ABTS could have been for an ELS
* or FCP IO. The port only generates this event when an ABTS
* fails to complete after one retry.
*/
static void
lpfc_sli_abts_err_handler(struct lpfc_hba *phba,
struct lpfc_iocbq *iocbq)
{
struct lpfc_nodelist *ndlp = NULL;
uint16_t rpi = 0, vpi = 0;
struct lpfc_vport *vport = NULL;
/* The rpi in the ulpContext is vport-sensitive. */
vpi = iocbq->iocb.un.asyncstat.sub_ctxt_tag;
rpi = iocbq->iocb.ulpContext;
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"3092 Port generated ABTS async event "
"on vpi %d rpi %d status 0x%x\n",
vpi, rpi, iocbq->iocb.ulpStatus);
vport = lpfc_find_vport_by_vpid(phba, vpi);
if (!vport)
goto err_exit;
ndlp = lpfc_findnode_rpi(vport, rpi);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
goto err_exit;
if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
lpfc_sli_abts_recover_port(vport, ndlp);
return;
err_exit:
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"3095 Event Context not found, no "
"action on vpi %d rpi %d status 0x%x, reason 0x%x\n",
iocbq->iocb.ulpContext, iocbq->iocb.ulpStatus,
vpi, rpi);
}
/* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port.
* @phba: pointer to HBA context object.
* @ndlp: nodelist pointer for the impacted rport.
* @axri: pointer to the wcqe containing the failed exchange.
*
* The driver calls this routine when it receives an ABORT_XRI_FCP CQE from the
* port. The port generates this event when an abort exchange request to an
* rport fails twice in succession with no reply. The abort could be originated
* by the driver or by the port. The ABTS could have been for an ELS or FCP IO.
*/
void
lpfc_sli4_abts_err_handler(struct lpfc_hba *phba,
struct lpfc_nodelist *ndlp,
struct sli4_wcqe_xri_aborted *axri)
{
struct lpfc_vport *vport;
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"3115 Node Context not found, driver "
"ignoring abts err event\n");
vport = ndlp->vport;
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"3116 Port generated FCP XRI ABORT event on "
"vpi %d rpi %d xri x%x status 0x%x\n",
ndlp->vport->vpi, ndlp->nlp_rpi,
bf_get(lpfc_wcqe_xa_xri, axri),
bf_get(lpfc_wcqe_xa_status, axri));
if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT)
lpfc_sli_abts_recover_port(vport, ndlp);
}
/**
* lpfc_sli_async_event_handler - ASYNC iocb handler function
* @phba: Pointer to HBA context object.
@ -8232,63 +8369,58 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
{
IOCB_t *icmd;
uint16_t evt_code;
uint16_t temp;
struct temp_event temp_event_data;
struct Scsi_Host *shost;
uint32_t *iocb_w;
icmd = &iocbq->iocb;
evt_code = icmd->un.asyncstat.evt_code;
temp = icmd->ulpContext;
if ((evt_code != ASYNC_TEMP_WARN) &&
(evt_code != ASYNC_TEMP_SAFE)) {
switch (evt_code) {
case ASYNC_TEMP_WARN:
case ASYNC_TEMP_SAFE:
temp_event_data.data = (uint32_t) icmd->ulpContext;
temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
if (evt_code == ASYNC_TEMP_WARN) {
temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
lpfc_printf_log(phba, KERN_ERR, LOG_TEMP,
"0347 Adapter is very hot, please take "
"corrective action. temperature : %d Celsius\n",
(uint32_t) icmd->ulpContext);
} else {
temp_event_data.event_code = LPFC_NORMAL_TEMP;
lpfc_printf_log(phba, KERN_ERR, LOG_TEMP,
"0340 Adapter temperature is OK now. "
"temperature : %d Celsius\n",
(uint32_t) icmd->ulpContext);
}
/* Send temperature change event to applications */
shost = lpfc_shost_from_vport(phba->pport);
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(temp_event_data), (char *) &temp_event_data,
LPFC_NL_VENDOR_ID);
break;
case ASYNC_STATUS_CN:
lpfc_sli_abts_err_handler(phba, iocbq);
break;
default:
iocb_w = (uint32_t *) icmd;
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0346 Ring %d handler: unexpected ASYNC_STATUS"
" evt_code 0x%x\n"
"W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n"
"W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n"
"W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n"
"W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n",
pring->ringno,
icmd->un.asyncstat.evt_code,
pring->ringno, icmd->un.asyncstat.evt_code,
iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3],
iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7],
iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11],
iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]);
return;
break;
}
temp_event_data.data = (uint32_t)temp;
temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
if (evt_code == ASYNC_TEMP_WARN) {
temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
lpfc_printf_log(phba,
KERN_ERR,
LOG_TEMP,
"0347 Adapter is very hot, please take "
"corrective action. temperature : %d Celsius\n",
temp);
}
if (evt_code == ASYNC_TEMP_SAFE) {
temp_event_data.event_code = LPFC_NORMAL_TEMP;
lpfc_printf_log(phba,
KERN_ERR,
LOG_TEMP,
"0340 Adapter temperature is OK now. "
"temperature : %d Celsius\n",
temp);
}
/* Send temperature change event to applications */
shost = lpfc_shost_from_vport(phba->pport);
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(temp_event_data), (char *) &temp_event_data,
LPFC_NL_VENDOR_ID);
}
@ -9247,6 +9379,14 @@ void
lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"3096 ABORT_XRI_CN completing on xri x%x "
"original iotag x%x, abort cmd iotag x%x "
"status 0x%x, reason 0x%x\n",
cmdiocb->iocb.un.acxri.abortContextTag,
cmdiocb->iocb.un.acxri.abortIoTag,
cmdiocb->iotag, rspiocb->iocb.ulpStatus,
rspiocb->iocb.un.ulpWord[4]);
lpfc_sli_release_iocbq(phba, cmdiocb);
return;
}