aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_hbadisc.c
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-09-07 11:52:10 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:57 -0400
commitea2151b4e142fa2de0319d9dd80413a997bf435a (patch)
tree1daa395a0b8584431c1b739af2761a840d013985 /drivers/scsi/lpfc/lpfc_hbadisc.c
parent977b5a0af6d22a1a0170057c19cde37eeac68acd (diff)
[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: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c143
1 files changed, 142 insertions, 1 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 887a5283605f..a1a70d9ffc2a 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -30,6 +30,7 @@
30#include <scsi/scsi_transport_fc.h> 30#include <scsi/scsi_transport_fc.h>
31 31
32#include "lpfc_hw.h" 32#include "lpfc_hw.h"
33#include "lpfc_nl.h"
33#include "lpfc_disc.h" 34#include "lpfc_disc.h"
34#include "lpfc_sli.h" 35#include "lpfc_sli.h"
35#include "lpfc_scsi.h" 36#include "lpfc_scsi.h"
@@ -274,6 +275,124 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
274 lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); 275 lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
275} 276}
276 277
278/**
279 * lpfc_alloc_fast_evt: Allocates data structure for posting event.
280 * @phba: Pointer to hba context object.
281 *
282 * This function is called from the functions which need to post
283 * events from interrupt context. This function allocates data
284 * structure required for posting event. It also keeps track of
285 * number of events pending and prevent event storm when there are
286 * too many events.
287 **/
288struct lpfc_fast_path_event *
289lpfc_alloc_fast_evt(struct lpfc_hba *phba) {
290 struct lpfc_fast_path_event *ret;
291
292 /* If there are lot of fast event do not exhaust memory due to this */
293 if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT)
294 return NULL;
295
296 ret = kzalloc(sizeof(struct lpfc_fast_path_event),
297 GFP_ATOMIC);
298 if (ret)
299 atomic_inc(&phba->fast_event_count);
300 INIT_LIST_HEAD(&ret->work_evt.evt_listp);
301 ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
302 return ret;
303}
304
305/**
306 * lpfc_free_fast_evt: Frees event data structure.
307 * @phba: Pointer to hba context object.
308 * @evt: Event object which need to be freed.
309 *
310 * This function frees the data structure required for posting
311 * events.
312 **/
313void
314lpfc_free_fast_evt(struct lpfc_hba *phba,
315 struct lpfc_fast_path_event *evt) {
316
317 atomic_dec(&phba->fast_event_count);
318 kfree(evt);
319}
320
321/**
322 * lpfc_send_fastpath_evt: Posts events generated from fast path.
323 * @phba: Pointer to hba context object.
324 * @evtp: Event data structure.
325 *
326 * This function is called from worker thread, when the interrupt
327 * context need to post an event. This function posts the event
328 * to fc transport netlink interface.
329 **/
330static void
331lpfc_send_fastpath_evt(struct lpfc_hba *phba,
332 struct lpfc_work_evt *evtp)
333{
334 unsigned long evt_category, evt_sub_category;
335 struct lpfc_fast_path_event *fast_evt_data;
336 char *evt_data;
337 uint32_t evt_data_size;
338 struct Scsi_Host *shost;
339
340 fast_evt_data = container_of(evtp, struct lpfc_fast_path_event,
341 work_evt);
342
343 evt_category = (unsigned long) fast_evt_data->un.fabric_evt.event_type;
344 evt_sub_category = (unsigned long) fast_evt_data->un.
345 fabric_evt.subcategory;
346 shost = lpfc_shost_from_vport(fast_evt_data->vport);
347 if (evt_category == FC_REG_FABRIC_EVENT) {
348 if (evt_sub_category == LPFC_EVENT_FCPRDCHKERR) {
349 evt_data = (char *) &fast_evt_data->un.read_check_error;
350 evt_data_size = sizeof(fast_evt_data->un.
351 read_check_error);
352 } else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) ||
353 (evt_sub_category == IOSTAT_NPORT_BSY)) {
354 evt_data = (char *) &fast_evt_data->un.fabric_evt;
355 evt_data_size = sizeof(fast_evt_data->un.fabric_evt);
356 } else {
357 lpfc_free_fast_evt(phba, fast_evt_data);
358 return;
359 }
360 } else if (evt_category == FC_REG_SCSI_EVENT) {
361 switch (evt_sub_category) {
362 case LPFC_EVENT_QFULL:
363 case LPFC_EVENT_DEVBSY:
364 evt_data = (char *) &fast_evt_data->un.scsi_evt;
365 evt_data_size = sizeof(fast_evt_data->un.scsi_evt);
366 break;
367 case LPFC_EVENT_CHECK_COND:
368 evt_data = (char *) &fast_evt_data->un.check_cond_evt;
369 evt_data_size = sizeof(fast_evt_data->un.
370 check_cond_evt);
371 break;
372 case LPFC_EVENT_VARQUEDEPTH:
373 evt_data = (char *) &fast_evt_data->un.queue_depth_evt;
374 evt_data_size = sizeof(fast_evt_data->un.
375 queue_depth_evt);
376 break;
377 default:
378 lpfc_free_fast_evt(phba, fast_evt_data);
379 return;
380 }
381 } else {
382 lpfc_free_fast_evt(phba, fast_evt_data);
383 return;
384 }
385
386 fc_host_post_vendor_event(shost,
387 fc_get_event_number(),
388 evt_data_size,
389 evt_data,
390 SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
391
392 lpfc_free_fast_evt(phba, fast_evt_data);
393 return;
394}
395
277static void 396static void
278lpfc_work_list_done(struct lpfc_hba *phba) 397lpfc_work_list_done(struct lpfc_hba *phba)
279{ 398{
@@ -345,6 +464,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
345 lpfc_unblock_mgmt_io(phba); 464 lpfc_unblock_mgmt_io(phba);
346 complete((struct completion *)(evtp->evt_arg2)); 465 complete((struct completion *)(evtp->evt_arg2));
347 break; 466 break;
467 case LPFC_EVT_FASTPATH_MGMT_EVT:
468 lpfc_send_fastpath_evt(phba, evtp);
469 free_evt = 0;
470 break;
348 } 471 }
349 if (free_evt) 472 if (free_evt)
350 kfree(evtp); 473 kfree(evtp);
@@ -1601,6 +1724,22 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1601 */ 1724 */
1602 lpfc_register_remote_port(vport, ndlp); 1725 lpfc_register_remote_port(vport, ndlp);
1603 } 1726 }
1727 if ((new_state == NLP_STE_MAPPED_NODE) &&
1728 (vport->stat_data_enabled)) {
1729 /*
1730 * A new target is discovered, if there is no buffer for
1731 * statistical data collection allocate buffer.
1732 */
1733 ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT,
1734 sizeof(struct lpfc_scsicmd_bkt),
1735 GFP_KERNEL);
1736
1737 if (!ndlp->lat_data)
1738 lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
1739 "0286 lpfc_nlp_state_cleanup failed to "
1740 "allocate statistical data buffer DID "
1741 "0x%x\n", ndlp->nlp_DID);
1742 }
1604 /* 1743 /*
1605 * if we added to Mapped list, but the remote port 1744 * if we added to Mapped list, but the remote port
1606 * registration failed or assigned a target id outside 1745 * registration failed or assigned a target id outside
@@ -3029,8 +3168,10 @@ lpfc_nlp_release(struct kref *kref)
3029 spin_unlock_irqrestore(&phba->ndlp_lock, flags); 3168 spin_unlock_irqrestore(&phba->ndlp_lock, flags);
3030 3169
3031 /* free ndlp memory for final ndlp release */ 3170 /* free ndlp memory for final ndlp release */
3032 if (NLP_CHK_FREE_REQ(ndlp)) 3171 if (NLP_CHK_FREE_REQ(ndlp)) {
3172 kfree(ndlp->lat_data);
3033 mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); 3173 mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
3174 }
3034} 3175}
3035 3176
3036/* This routine bumps the reference count for a ndlp structure to ensure 3177/* This routine bumps the reference count for a ndlp structure to ensure