diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-09-07 11:52:10 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-10-13 09:28:57 -0400 |
commit | ea2151b4e142fa2de0319d9dd80413a997bf435a (patch) | |
tree | 1daa395a0b8584431c1b739af2761a840d013985 /drivers/scsi/lpfc/lpfc_hbadisc.c | |
parent | 977b5a0af6d22a1a0170057c19cde37eeac68acd (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.c | 143 |
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 | **/ | ||
288 | struct lpfc_fast_path_event * | ||
289 | lpfc_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 | **/ | ||
313 | void | ||
314 | lpfc_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 | **/ | ||
330 | static void | ||
331 | lpfc_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 | |||
277 | static void | 396 | static void |
278 | lpfc_work_list_done(struct lpfc_hba *phba) | 397 | lpfc_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 |