Commit ea2151b4 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.2.8 v2 : Add statistical reporting control and additional fc vendor events

Added support for new sysfs attributes: lpfc_stat_data_ctrl and
lpfc_max_scsicmpl_time. The attributes control statistical reporting
of io load.

Added support for new fc vendor events for error reporting.
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 977b5a0a
...@@ -40,6 +40,8 @@ struct lpfc_sli2_slim; ...@@ -40,6 +40,8 @@ struct lpfc_sli2_slim;
#define LPFC_MIN_TGT_QDEPTH 100 #define LPFC_MIN_TGT_QDEPTH 100
#define LPFC_MAX_TGT_QDEPTH 0xFFFF #define LPFC_MAX_TGT_QDEPTH 0xFFFF
#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data
collection. */
/* /*
* Following time intervals are used of adjusting SCSI device * Following time intervals are used of adjusting SCSI device
* queue depths when there are driver resource error or Firmware * queue depths when there are driver resource error or Firmware
...@@ -381,6 +383,8 @@ struct lpfc_vport { ...@@ -381,6 +383,8 @@ struct lpfc_vport {
struct lpfc_debugfs_trc *disc_trc; struct lpfc_debugfs_trc *disc_trc;
atomic_t disc_trc_cnt; atomic_t disc_trc_cnt;
#endif #endif
uint8_t stat_data_enabled;
uint8_t stat_data_blocked;
}; };
struct hbq_s { struct hbq_s {
...@@ -641,6 +645,17 @@ struct lpfc_hba { ...@@ -641,6 +645,17 @@ struct lpfc_hba {
uint32_t buffer_tag_count; uint32_t buffer_tag_count;
int wait_4_mlo_maint_flg; int wait_4_mlo_maint_flg;
wait_queue_head_t wait_4_mlo_m_q; wait_queue_head_t wait_4_mlo_m_q;
/* data structure used for latency data collection */
#define LPFC_NO_BUCKET 0
#define LPFC_LINEAR_BUCKET 1
#define LPFC_POWER2_BUCKET 2
uint8_t bucket_type;
uint32_t bucket_base;
uint32_t bucket_step;
/* Maximum number of events that can be outstanding at any time*/
#define LPFC_MAX_EVT_COUNT 512
atomic_t fast_event_count;
}; };
static inline struct Scsi_Host * static inline struct Scsi_Host *
...@@ -699,15 +714,3 @@ lpfc_sli_read_hs(struct lpfc_hba *phba) ...@@ -699,15 +714,3 @@ lpfc_sli_read_hs(struct lpfc_hba *phba)
return; return;
} }
#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
#define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature
event */
struct temp_event {
uint32_t event_type;
uint32_t event_code;
uint32_t data;
};
#define LPFC_CRIT_TEMP 0x1
#define LPFC_THRESHOLD_TEMP 0x2
#define LPFC_NORMAL_TEMP 0x3
This diff is collapsed.
...@@ -294,6 +294,12 @@ void lpfc_ramp_down_queue_handler(struct lpfc_hba *); ...@@ -294,6 +294,12 @@ void lpfc_ramp_down_queue_handler(struct lpfc_hba *);
void lpfc_ramp_up_queue_handler(struct lpfc_hba *); void lpfc_ramp_up_queue_handler(struct lpfc_hba *);
void lpfc_scsi_dev_block(struct lpfc_hba *); void lpfc_scsi_dev_block(struct lpfc_hba *);
void
lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
struct lpfc_fast_path_event *lpfc_alloc_fast_evt(struct lpfc_hba *);
void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *);
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5 #define HBA_EVENT_RSCN 5
#define HBA_EVENT_LINK_UP 2 #define HBA_EVENT_LINK_UP 2
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
......
...@@ -37,6 +37,7 @@ enum lpfc_work_type { ...@@ -37,6 +37,7 @@ enum lpfc_work_type {
LPFC_EVT_KILL, LPFC_EVT_KILL,
LPFC_EVT_ELS_RETRY, LPFC_EVT_ELS_RETRY,
LPFC_EVT_DEV_LOSS, LPFC_EVT_DEV_LOSS,
LPFC_EVT_FASTPATH_MGMT_EVT,
}; };
/* structure used to queue event to the discovery tasklet */ /* structure used to queue event to the discovery tasklet */
...@@ -47,6 +48,24 @@ struct lpfc_work_evt { ...@@ -47,6 +48,24 @@ struct lpfc_work_evt {
enum lpfc_work_type evt; enum lpfc_work_type evt;
}; };
struct lpfc_scsi_check_condition_event;
struct lpfc_scsi_varqueuedepth_event;
struct lpfc_scsi_event_header;
struct lpfc_fabric_event_header;
struct lpfc_fcprdchkerr_event;
/* structure used for sending events from fast path */
struct lpfc_fast_path_event {
struct lpfc_work_evt work_evt;
struct lpfc_vport *vport;
union {
struct lpfc_scsi_check_condition_event check_cond_evt;
struct lpfc_scsi_varqueuedepth_event queue_depth_evt;
struct lpfc_scsi_event_header scsi_evt;
struct lpfc_fabric_event_header fabric_evt;
struct lpfc_fcprdchkerr_event read_check_error;
} un;
};
struct lpfc_nodelist { struct lpfc_nodelist {
struct list_head nlp_listp; struct list_head nlp_listp;
...@@ -91,6 +110,7 @@ struct lpfc_nodelist { ...@@ -91,6 +110,7 @@ struct lpfc_nodelist {
atomic_t cmd_pending; atomic_t cmd_pending;
uint32_t cmd_qdepth; uint32_t cmd_qdepth;
unsigned long last_change_time; unsigned long last_change_time;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
}; };
/* Defines for nlp_flag (uint32) */ /* Defines for nlp_flag (uint32) */
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
...@@ -5084,6 +5085,116 @@ lpfc_els_flush_all_cmd(struct lpfc_hba *phba) ...@@ -5084,6 +5085,116 @@ lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
return; return;
} }
/**
* lpfc_send_els_failure_event: Posts an ELS command failure event.
* @phba: Pointer to hba context object.
* @cmdiocbp: Pointer to command iocb which reported error.
* @rspiocbp: Pointer to response iocb which reported error.
*
* This function sends an event when there is an ELS command
* failure.
**/
void
lpfc_send_els_failure_event(struct lpfc_hba *phba,
struct lpfc_iocbq *cmdiocbp,
struct lpfc_iocbq *rspiocbp)
{
struct lpfc_vport *vport = cmdiocbp->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_lsrjt_event lsrjt_event;
struct lpfc_fabric_event_header fabric_event;
struct ls_rjt stat;
struct lpfc_nodelist *ndlp;
uint32_t *pcmd;
ndlp = cmdiocbp->context1;
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
return;
if (rspiocbp->iocb.ulpStatus == IOSTAT_LS_RJT) {
lsrjt_event.header.event_type = FC_REG_ELS_EVENT;
lsrjt_event.header.subcategory = LPFC_EVENT_LSRJT_RCV;
memcpy(lsrjt_event.header.wwpn, &ndlp->nlp_portname,
sizeof(struct lpfc_name));
memcpy(lsrjt_event.header.wwnn, &ndlp->nlp_nodename,
sizeof(struct lpfc_name));
pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
cmdiocbp->context2)->virt);
lsrjt_event.command = *pcmd;
stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]);
lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode;
lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp;
fc_host_post_vendor_event(shost,
fc_get_event_number(),
sizeof(lsrjt_event),
(char *)&lsrjt_event,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
return;
}
if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) ||
(rspiocbp->iocb.ulpStatus == IOSTAT_FABRIC_BSY)) {
fabric_event.event_type = FC_REG_FABRIC_EVENT;
if (rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY)
fabric_event.subcategory = LPFC_EVENT_PORT_BUSY;
else
fabric_event.subcategory = LPFC_EVENT_FABRIC_BUSY;
memcpy(fabric_event.wwpn, &ndlp->nlp_portname,
sizeof(struct lpfc_name));
memcpy(fabric_event.wwnn, &ndlp->nlp_nodename,
sizeof(struct lpfc_name));
fc_host_post_vendor_event(shost,
fc_get_event_number(),
sizeof(fabric_event),
(char *)&fabric_event,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
return;
}
}
/**
* lpfc_send_els_event: Posts unsolicited els event.
* @vport: Pointer to vport object.
* @ndlp: Pointer FC node object.
* @cmd: ELS command code.
*
* This function posts an event when there is an incoming
* unsolicited ELS command.
**/
static void
lpfc_send_els_event(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp,
uint32_t cmd)
{
struct lpfc_els_event_header els_data;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
els_data.event_type = FC_REG_ELS_EVENT;
switch (cmd) {
case ELS_CMD_PLOGI:
els_data.subcategory = LPFC_EVENT_PLOGI_RCV;
break;
case ELS_CMD_PRLO:
els_data.subcategory = LPFC_EVENT_PRLO_RCV;
break;
case ELS_CMD_ADISC:
els_data.subcategory = LPFC_EVENT_ADISC_RCV;
break;
default:
return;
}
memcpy(els_data.wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name));
memcpy(els_data.wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name));
fc_host_post_vendor_event(shost,
fc_get_event_number(),
sizeof(els_data),
(char *)&els_data,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
return;
}
/** /**
* lpfc_els_unsol_buffer: Process an unsolicited event data buffer. * lpfc_els_unsol_buffer: Process an unsolicited event data buffer.
* @phba: pointer to lpfc hba data structure. * @phba: pointer to lpfc hba data structure.
...@@ -5185,6 +5296,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -5185,6 +5296,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
phba->fc_stat.elsRcvPLOGI++; phba->fc_stat.elsRcvPLOGI++;
ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
lpfc_send_els_event(vport, ndlp, cmd);
if (vport->port_state < LPFC_DISC_AUTH) { if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) || if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) { (phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
...@@ -5234,6 +5346,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -5234,6 +5346,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
did, vport->port_state, ndlp->nlp_flag); did, vport->port_state, ndlp->nlp_flag);
phba->fc_stat.elsRcvPRLO++; phba->fc_stat.elsRcvPRLO++;
lpfc_send_els_event(vport, ndlp, cmd);
if (vport->port_state < LPFC_DISC_AUTH) { if (vport->port_state < LPFC_DISC_AUTH) {
rjt_err = LSRJT_UNABLE_TPC; rjt_err = LSRJT_UNABLE_TPC;
break; break;
...@@ -5251,6 +5364,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -5251,6 +5364,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
"RCV ADISC: did:x%x/ste:x%x flg:x%x", "RCV ADISC: did:x%x/ste:x%x flg:x%x",
did, vport->port_state, ndlp->nlp_flag); did, vport->port_state, ndlp->nlp_flag);
lpfc_send_els_event(vport, ndlp, cmd);
phba->fc_stat.elsRcvADISC++; phba->fc_stat.elsRcvADISC++;
if (vport->port_state < LPFC_DISC_AUTH) { if (vport->port_state < LPFC_DISC_AUTH) {
rjt_err = LSRJT_UNABLE_TPC; rjt_err = LSRJT_UNABLE_TPC;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
...@@ -274,6 +275,124 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ...@@ -274,6 +275,124 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
} }
/**
* lpfc_alloc_fast_evt: Allocates data structure for posting event.
* @phba: Pointer to hba context object.
*
* This function is called from the functions which need to post
* events from interrupt context. This function allocates data
* structure required for posting event. It also keeps track of
* number of events pending and prevent event storm when there are
* too many events.
**/
struct lpfc_fast_path_event *
lpfc_alloc_fast_evt(struct lpfc_hba *phba) {
struct lpfc_fast_path_event *ret;
/* If there are lot of fast event do not exhaust memory due to this */
if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT)
return NULL;
ret = kzalloc(sizeof(struct lpfc_fast_path_event),
GFP_ATOMIC);
if (ret)
atomic_inc(&phba->fast_event_count);
INIT_LIST_HEAD(&ret->work_evt.evt_listp);
ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
return ret;
}
/**
* lpfc_free_fast_evt: Frees event data structure.
* @phba: Pointer to hba context object.
* @evt: Event object which need to be freed.
*
* This function frees the data structure required for posting
* events.
**/
void
lpfc_free_fast_evt(struct lpfc_hba *phba,
struct lpfc_fast_path_event *evt) {
atomic_dec(&phba->fast_event_count);
kfree(evt);
}
/**
* lpfc_send_fastpath_evt: Posts events generated from fast path.
* @phba: Pointer to hba context object.
* @evtp: Event data structure.
*
* This function is called from worker thread, when the interrupt
* context need to post an event. This function posts the event
* to fc transport netlink interface.
**/
static void
lpfc_send_fastpath_evt(struct lpfc_hba *phba,
struct lpfc_work_evt *evtp)
{
unsigned long evt_category, evt_sub_category;
struct lpfc_fast_path_event *fast_evt_data;
char *evt_data;
uint32_t evt_data_size;
struct Scsi_Host *shost;
fast_evt_data = container_of(evtp, struct lpfc_fast_path_event,
work_evt);
evt_category = (unsigned long) fast_evt_data->un.fabric_evt.event_type;
evt_sub_category = (unsigned long) fast_evt_data->un.
fabric_evt.subcategory;
shost = lpfc_shost_from_vport(fast_evt_data->vport);
if (evt_category == FC_REG_FABRIC_EVENT) {
if (evt_sub_category == LPFC_EVENT_FCPRDCHKERR) {
evt_data = (char *) &fast_evt_data->un.read_check_error;
evt_data_size = sizeof(fast_evt_data->un.
read_check_error);
} else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) ||
(evt_sub_category == IOSTAT_NPORT_BSY)) {
evt_data = (char *) &fast_evt_data->un.fabric_evt;
evt_data_size = sizeof(fast_evt_data->un.fabric_evt);
} else {
lpfc_free_fast_evt(phba, fast_evt_data);
return;
}
} else if (evt_category == FC_REG_SCSI_EVENT) {
switch (evt_sub_category) {
case LPFC_EVENT_QFULL:
case LPFC_EVENT_DEVBSY:
evt_data = (char *) &fast_evt_data->un.scsi_evt;
evt_data_size = sizeof(fast_evt_data->un.scsi_evt);
break;
case LPFC_EVENT_CHECK_COND:
evt_data = (char *) &fast_evt_data->un.check_cond_evt;
evt_data_size = sizeof(fast_evt_data->un.
check_cond_evt);
break;
case LPFC_EVENT_VARQUEDEPTH:
evt_data = (char *) &fast_evt_data->un.queue_depth_evt;
evt_data_size = sizeof(fast_evt_data->un.
queue_depth_evt);
break;
default:
lpfc_free_fast_evt(phba, fast_evt_data);
return;
}
} else {
lpfc_free_fast_evt(phba, fast_evt_data);
return;
}
fc_host_post_vendor_event(shost,
fc_get_event_number(),
evt_data_size,
evt_data,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
lpfc_free_fast_evt(phba, fast_evt_data);
return;
}
static void static void
lpfc_work_list_done(struct lpfc_hba *phba) lpfc_work_list_done(struct lpfc_hba *phba)
{ {
...@@ -345,6 +464,10 @@ lpfc_work_list_done(struct lpfc_hba *phba) ...@@ -345,6 +464,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
lpfc_unblock_mgmt_io(phba); lpfc_unblock_mgmt_io(phba);
complete((struct completion *)(evtp->evt_arg2)); complete((struct completion *)(evtp->evt_arg2));
break; break;
case LPFC_EVT_FASTPATH_MGMT_EVT:
lpfc_send_fastpath_evt(phba, evtp);
free_evt = 0;
break;
} }
if (free_evt) if (free_evt)
kfree(evtp); kfree(evtp);
...@@ -1601,6 +1724,22 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1601,6 +1724,22 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
*/ */
lpfc_register_remote_port(vport, ndlp); lpfc_register_remote_port(vport, ndlp);
} }
if ((new_state == NLP_STE_MAPPED_NODE) &&
(vport->stat_data_enabled)) {
/*
* A new target is discovered, if there is no buffer for
* statistical data collection allocate buffer.
*/
ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT,
sizeof(struct lpfc_scsicmd_bkt),
GFP_KERNEL);
if (!ndlp->lat_data)
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
"0286 lpfc_nlp_state_cleanup failed to "
"allocate statistical data buffer DID "
"0x%x\n", ndlp->nlp_DID);
}
/* /*
* if we added to Mapped list, but the remote port * if we added to Mapped list, but the remote port
* registration failed or assigned a target id outside * registration failed or assigned a target id outside
...@@ -3029,8 +3168,10 @@ lpfc_nlp_release(struct kref *kref) ...@@ -3029,8 +3168,10 @@ lpfc_nlp_release(struct kref *kref)
spin_unlock_irqrestore(&phba->ndlp_lock, flags); spin_unlock_irqrestore(&phba->ndlp_lock, flags);
/* free ndlp memory for final ndlp release */ /* free ndlp memory for final ndlp release */
if (NLP_CHK_FREE_REQ(ndlp)) if (NLP_CHK_FREE_REQ(ndlp)) {
kfree(ndlp->lat_data);
mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
}
} }
/* This routine bumps the reference count for a ndlp structure to ensure /* This routine bumps the reference count for a ndlp structure to ensure
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
...@@ -815,6 +816,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) ...@@ -815,6 +816,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
unsigned long temperature; unsigned long temperature;
struct temp_event temp_event_data; struct temp_event temp_event_data;
struct Scsi_Host *shost; struct Scsi_Host *shost;
struct lpfc_board_event_header board_event;
/* If the pci channel is offline, ignore possible errors, /* If the pci channel is offline, ignore possible errors,
* since we cannot communicate with the pci card anyway. */ * since we cannot communicate with the pci card anyway. */
...@@ -824,6 +826,16 @@ lpfc_handle_eratt(struct lpfc_hba *phba) ...@@ -824,6 +826,16 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
if (!phba->cfg_enable_hba_reset) if (!phba->cfg_enable_hba_reset)
return; return;
/* Send an internal error event to mgmt application */
board_event.event_type = FC_REG_BOARD_EVENT;
board_event.subcategory = LPFC_EVENT_PORTINTERR;
shost = lpfc_shost_from_vport(phba->pport);
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(board_event),
(char *) &board_event,
SCSI_NL_VID_TYPE_PCI
| PCI_VENDOR_ID_EMULEX);
if (phba->work_hs & HS_FFER6) { if (phba->work_hs & HS_FFER6) {
/* Re-establishing Link */ /* Re-establishing Link */
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
...@@ -2345,6 +2357,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -2345,6 +2357,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
int i, hbq_count; int i, hbq_count;
uint16_t iotag; uint16_t iotag;
int bars = pci_select_bars(pdev, IORESOURCE_MEM); int bars = pci_select_bars(pdev, IORESOURCE_MEM);
struct lpfc_adapter_event_header adapter_event;
if (pci_enable_device_mem(pdev)) if (pci_enable_device_mem(pdev))
goto out; goto out;
...@@ -2355,6 +2368,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -2355,6 +2368,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (!phba) if (!phba)
goto out_release_regions; goto out_release_regions;
atomic_set(&phba->fast_event_count, 0);
spin_lock_init(&phba->hbalock); spin_lock_init(&phba->hbalock);
/* Initialize ndlp management spinlock */ /* Initialize ndlp management spinlock */
...@@ -2626,6 +2640,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -2626,6 +2640,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
lpfc_printf_log(phba, KERN_INFO, LOG_INIT, lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0428 Perform SCSI scan\n"); "0428 Perform SCSI scan\n");
/* Send board arrival event to upper layer */
adapter_event.event_type = FC_REG_ADAPTER_EVENT;
adapter_event.subcategory = LPFC_EVENT_ARRIVAL;
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(adapter_event),
(char *) &adapter_event,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
scsi_scan_host(shost); scsi_scan_host(shost);
return 0; return 0;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
......
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* 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. *
*******************************************************************/
/* Event definitions for RegisterForEvent */
#define FC_REG_LINK_EVENT 0x0001 /* link up / down events */
#define FC_REG_RSCN_EVENT 0x0002 /* RSCN events */
#define FC_REG_CT_EVENT 0x0004 /* CT request events */
#define FC_REG_DUMP_EVENT 0x0008 /* Dump events */
#define FC_REG_TEMPERATURE_EVENT 0x0010 /* temperature events */
#define FC_REG_ELS_EVENT 0x0020 /* lpfc els events */
#define FC_REG_FABRIC_EVENT 0x0040 /* lpfc fabric events */
#define FC_REG_SCSI_EVENT 0x0080 /* lpfc scsi events */
#define FC_REG_BOARD_EVENT 0x0100 /* lpfc board events */
#define FC_REG_ADAPTER_EVENT 0x0200 /* lpfc adapter events */
#define FC_REG_EVENT_MASK (FC_REG_LINK_EVENT | \
FC_REG_RSCN_EVENT | \
FC_REG_CT_EVENT | \
FC_REG_DUMP_EVENT | \
FC_REG_TEMPERATURE_EVENT | \
FC_REG_ELS_EVENT | \
FC_REG_FABRIC_EVENT | \
FC_REG_SCSI_EVENT | \
FC_REG_BOARD_EVENT | \
FC_REG_ADAPTER_EVENT)
/* Temperature events */
#define LPFC_CRIT_TEMP 0x1
#define LPFC_THRESHOLD_TEMP 0x2
#define LPFC_NORMAL_TEMP 0x3
/*
* All net link event payloads will begin with and event type
* and subcategory. The event type must come first.
* The subcategory further defines the data that follows in the rest
* of the payload. Each category will have its own unique header plus
* any addtional data unique to the subcategory.
* The payload sent via the fc transport is one-way driver->application.
*/
/* els event header */
struct lpfc_els_event_header {
uint32_t event_type;
uint32_t subcategory;
uint8_t wwpn[8];
uint8_t wwnn[8];
};
/* subcategory codes for FC_REG_ELS_EVENT */
#define LPFC_EVENT_PLOGI_RCV 0x01
#define LPFC_EVENT_PRLO_RCV 0x02
#define LPFC_EVENT_ADISC_RCV 0x04
#define LPFC_EVENT_LSRJT_RCV 0x08
/* special els lsrjt event */
struct lpfc_lsrjt_event {
struct lpfc_els_event_header header;
uint32_t command;
uint32_t reason_code;
uint32_t explanation;
};
/* fabric event header */
struct lpfc_fabric_event_header {
uint32_t event_type;
uint32_t subcategory;
uint8_t wwpn[8];
uint8_t wwnn[8];
};
/* subcategory codes for FC_REG_FABRIC_EVENT */
#define LPFC_EVENT_FABRIC_BUSY 0x01
#define LPFC_EVENT_PORT_BUSY 0x02
#define LPFC_EVENT_FCPRDCHKERR 0x04
/* special case fabric fcprdchkerr event */
struct lpfc_fcprdchkerr_event {
struct lpfc_fabric_event_header header;
uint32_t lun;
uint32_t opcode;
uint32_t fcpiparam;
};
/* scsi event header */
struct lpfc_scsi_event_header {
uint32_t event_type;
uint32_t subcategory;
uint32_t lun;
uint8_t wwpn[8];
uint8_t wwnn[8];
};
/* subcategory codes for FC_REG_SCSI_EVENT */
#define LPFC_EVENT_QFULL 0x0001
#define LPFC_EVENT_DEVBSY 0x0002
#define LPFC_EVENT_CHECK_COND 0x0004
#define LPFC_EVENT_LUNRESET 0x0008
#define LPFC_EVENT_TGTRESET 0x0010
#define LPFC_EVENT_BUSRESET 0x0020
#define LPFC_EVENT_VARQUEDEPTH 0x0040
/* special case scsi varqueuedepth event */
struct lpfc_scsi_varqueuedepth_event {
struct lpfc_scsi_event_header scsi_event;
uint32_t oldval;
uint32_t newval;
};
/* special case scsi check condition event */
struct lpfc_scsi_check_condition_event {
struct lpfc_scsi_event_header scsi_event;
uint8_t sense_key;
uint8_t asc;
uint8_t ascq;
};
/* event codes for FC_REG_BOARD_EVENT */
#define LPFC_EVENT_PORTINTERR 0x01
/* board event header */
struct lpfc_board_event_header {
uint32_t event_type;
uint32_t subcategory;
};
/* event codes for FC_REG_ADAPTER_EVENT */
#define LPFC_EVENT_ARRIVAL 0x01
/* adapter event header */
struct lpfc_adapter_event_header {
uint32_t event_type;
uint32_t subcategory;
};
/* event codes for temp_event */
#define LPFC_CRIT_TEMP 0x1
#define LPFC_THRESHOLD_TEMP 0x2
#define LPFC_NORMAL_TEMP 0x3
struct temp_event {
uint32_t event_type;
uint32_t event_code;
uint32_t data;
};
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
......
This diff is collapsed.
...@@ -107,6 +107,10 @@ struct fcp_cmnd { ...@@ -107,6 +107,10 @@ struct fcp_cmnd {
}; };
struct lpfc_scsicmd_bkt {
uint32_t cmd_count;
};
struct lpfc_scsi_buf { struct lpfc_scsi_buf {
struct list_head list; struct list_head list;
struct scsi_cmnd *pCmd; struct scsi_cmnd *pCmd;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
...@@ -1610,6 +1611,17 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -1610,6 +1611,17 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (cmdiocbp) { if (cmdiocbp) {
if (cmdiocbp->iocb_cmpl) { if (cmdiocbp->iocb_cmpl) {
/*
* If an ELS command failed send an event to mgmt
* application.
*/
if (saveq->iocb.ulpStatus &&
(pring->ringno == LPFC_ELS_RING) &&
(cmdiocbp->iocb.ulpCommand ==
CMD_ELS_REQUEST64_CR))
lpfc_send_els_failure_event(phba,
cmdiocbp, saveq);
/* /*
* Post all ELS completions to the worker thread. * Post all ELS completions to the worker thread.
* All other are passed to the completion callback. * All other are passed to the completion callback.
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
#include "lpfc_hw.h" #include "lpfc_hw.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
...@@ -745,3 +746,82 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) ...@@ -745,3 +746,82 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
scsi_host_put(lpfc_shost_from_vport(vports[i])); scsi_host_put(lpfc_shost_from_vport(vports[i]));
kfree(vports); kfree(vports);
} }
/**
* lpfc_vport_reset_stat_data: Reset the statistical data for the vport.
* @vport: Pointer to vport object.
*
* This function resets the statistical data for the vport. This function
* is called with the host_lock held
**/
void
lpfc_vport_reset_stat_data(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
if (ndlp->lat_data)
memset(ndlp->lat_data, 0, LPFC_MAX_BUCKET_COUNT *
sizeof(struct lpfc_scsicmd_bkt));
}
}
/**
* lpfc_alloc_bucket: Allocate data buffer required for collecting
* statistical data.
* @vport: Pointer to vport object.
*
* This function allocates data buffer required for all the FC
* nodes of the vport to collect statistical data.
**/
void
lpfc_alloc_bucket(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
kfree(ndlp->lat_data);
ndlp->lat_data = NULL;
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT,
sizeof(struct lpfc_scsicmd_bkt),
GFP_ATOMIC);
if (!ndlp->lat_data)
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
"0287 lpfc_alloc_bucket failed to "
"allocate statistical data buffer DID "
"0x%x\n", ndlp->nlp_DID);
}
}
}
/**
* lpfc_free_bucket: Free data buffer required for collecting
* statistical data.
* @vport: Pointer to vport object.
*
* Th function frees statistical data buffer of all the FC
* nodes of the vport.
**/
void
lpfc_free_bucket(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
kfree(ndlp->lat_data);
ndlp->lat_data = NULL;
}
}
...@@ -112,4 +112,8 @@ struct vport_cmd_tag { ...@@ -112,4 +112,8 @@ struct vport_cmd_tag {
void lpfc_vport_set_state(struct lpfc_vport *vport, void lpfc_vport_set_state(struct lpfc_vport *vport,
enum fc_vport_state new_state); enum fc_vport_state new_state);
void lpfc_vport_reset_stat_data(struct lpfc_vport *);
void lpfc_alloc_bucket(struct lpfc_vport *);
void lpfc_free_bucket(struct lpfc_vport *);
#endif /* H_LPFC_VPORT */ #endif /* H_LPFC_VPORT */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment