[patch 6/6] statistics infrastructure - exploitation: zfcp This patch instruments the zfcp driver and makes it feed statistics data into the statistics infrastructure. Signed-off-by: Martin Peschke <mp3@xxxxxxxxxx> Acked-by: Andreas Herrmann <aherrman@xxxxxxxxxx> --- Makefile | 4 - zfcp_aux.c | 22 ++++++ zfcp_ccw.c | 7 ++ zfcp_def.h | 31 ++++++++- zfcp_erp.c | 4 + zfcp_ext.h | 6 + zfcp_fsf.c | 60 +++++++++++++++++- zfcp_qdio.c | 5 + zfcp_scsi.c | 14 ++++ zfcp_stat.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 338 insertions(+), 10 deletions(-) diff -Nurp f/drivers/s390/scsi/Makefile g/drivers/s390/scsi/Makefile --- f/drivers/s390/scsi/Makefile 2005-10-28 02:02:08.000000000 +0200 +++ g/drivers/s390/scsi/Makefile 2005-12-14 16:01:55.000000000 +0100 @@ -3,7 +3,7 @@ # zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ - zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ - zfcp_sysfs_unit.o zfcp_sysfs_driver.o + zfcp_fsf.o zfcp_dbf.o zfcp_stat.o zfcp_sysfs_adapter.o \ + zfcp_sysfs_port.o zfcp_sysfs_unit.o zfcp_sysfs_driver.o obj-$(CONFIG_ZFCP) += zfcp.o diff -Nurp f/drivers/s390/scsi/zfcp_aux.c g/drivers/s390/scsi/zfcp_aux.c --- f/drivers/s390/scsi/zfcp_aux.c 2005-12-14 12:51:26.000000000 +0100 +++ g/drivers/s390/scsi/zfcp_aux.c 2005-12-14 16:01:55.000000000 +0100 @@ -778,15 +778,20 @@ zfcp_unit_enqueue(struct zfcp_port *port unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); + if (zfcp_unit_statistic_register(unit)) + return NULL; + /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); if (device_register(&unit->sysfs_device)) { + zfcp_unit_statistic_unregister(unit); kfree(unit); return NULL; } if (zfcp_sysfs_unit_create_files(&unit->sysfs_device)) { + zfcp_unit_statistic_unregister(unit); device_unregister(&unit->sysfs_device); return NULL; } @@ -826,6 +831,7 @@ zfcp_unit_dequeue(struct zfcp_unit *unit list_del(&unit->list); write_unlock_irq(&zfcp_data.config_lock); unit->port->units--; + zfcp_unit_statistic_unregister(unit); zfcp_port_put(unit->port); zfcp_sysfs_unit_remove_files(&unit->sysfs_device); device_unregister(&unit->sysfs_device); @@ -837,6 +843,16 @@ zfcp_mempool_alloc(gfp_t gfp_mask, void return kmalloc((size_t) size, gfp_mask); } +static void * +zfcp_mempool_alloc_fsf_req_scsi(unsigned int __nocast gfp_mask, void *data) +{ + struct zfcp_adapter *adapter = (struct zfcp_adapter *)data; + void *ptr = kmalloc(sizeof(struct zfcp_fsf_req_pool_element), gfp_mask); + if (!ptr) + statistic_inc(adapter->stat_low_mem_scsi, 0); + return ptr; +} + static void zfcp_mempool_free(void *element, void *size) { @@ -864,8 +880,8 @@ zfcp_allocate_low_mem_buffers(struct zfc adapter->pool.fsf_req_scsi = mempool_create(ZFCP_POOL_FSF_REQ_SCSI_NR, - zfcp_mempool_alloc, zfcp_mempool_free, (void *) - sizeof(struct zfcp_fsf_req_pool_element)); + zfcp_mempool_alloc_fsf_req_scsi, + zfcp_mempool_free, (void *)adapter); if (NULL == adapter->pool.fsf_req_scsi) return -ENOMEM; diff -Nurp f/drivers/s390/scsi/zfcp_ccw.c g/drivers/s390/scsi/zfcp_ccw.c --- f/drivers/s390/scsi/zfcp_ccw.c 2005-10-28 02:02:08.000000000 +0200 +++ g/drivers/s390/scsi/zfcp_ccw.c 2005-12-14 16:01:55.000000000 +0100 @@ -163,6 +163,10 @@ zfcp_ccw_set_online(struct ccw_device *c retval = zfcp_adapter_debug_register(adapter); if (retval) goto out; + retval = zfcp_adapter_statistic_register(adapter); + if (retval) + goto out_stat_create; + retval = zfcp_erp_thread_setup(adapter); if (retval) { ZFCP_LOG_INFO("error: start of error recovery thread for " @@ -183,6 +187,8 @@ zfcp_ccw_set_online(struct ccw_device *c out_scsi_register: zfcp_erp_thread_kill(adapter); out_erp_thread: + zfcp_adapter_statistic_unregister(adapter); + out_stat_create: zfcp_adapter_debug_unregister(adapter); out: up(&zfcp_data.config_sema); @@ -209,6 +215,7 @@ zfcp_ccw_set_offline(struct ccw_device * zfcp_erp_wait(adapter); zfcp_adapter_scsi_unregister(adapter); zfcp_erp_thread_kill(adapter); + zfcp_adapter_statistic_unregister(adapter); zfcp_adapter_debug_unregister(adapter); up(&zfcp_data.config_sema); return 0; diff -Nurp f/drivers/s390/scsi/zfcp_def.h g/drivers/s390/scsi/zfcp_def.h --- f/drivers/s390/scsi/zfcp_def.h 2005-10-28 02:02:08.000000000 +0200 +++ g/drivers/s390/scsi/zfcp_def.h 2005-12-14 16:01:55.000000000 +0100 @@ -58,6 +58,8 @@ #include <asm/qdio.h> #include <asm/debug.h> #include <asm/ebcdic.h> +#include <asm/timex.h> +#include <linux/statistic.h> #include <linux/mempool.h> #include <linux/syscalls.h> #include <linux/ioctl.h> @@ -66,7 +68,7 @@ /********************* GENERAL DEFINES *********************************/ /* zfcp version number, it consists of major, minor, and patch-level number */ -#define ZFCP_VERSION "4.5.0" +#define ZFCP_VERSION "4.6.0" /** * zfcp_sg_to_address - determine kernel address from struct scatterlist @@ -978,6 +980,12 @@ struct zfcp_adapter { struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct qdio_initialize qdio_init_data; /* for qdio_establish */ struct device generic_services; /* directory for WKA ports */ + struct statistic_interface *stat_if; + struct statistic *stat_qdio_outb_full; + struct statistic *stat_qdio_outb; + struct statistic *stat_qdio_inb; + struct statistic *stat_low_mem_scsi; + struct statistic *stat_erp; }; /* @@ -1024,6 +1032,24 @@ struct zfcp_unit { struct scsi_device *device; /* scsi device struct pointer */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; + atomic_t read_num; + atomic_t write_num; + struct statistic_interface *stat_if; + struct statistic *stat_sizes_scsi_write; + struct statistic *stat_sizes_scsi_read; + struct statistic *stat_sizes_scsi_nodata; + struct statistic *stat_sizes_scsi_nofit; + struct statistic *stat_sizes_scsi_nomem; + struct statistic *stat_sizes_timedout_write; + struct statistic *stat_sizes_timedout_read; + struct statistic *stat_sizes_timedout_nodata; + struct statistic *stat_latencies_scsi_write; + struct statistic *stat_latencies_scsi_read; + struct statistic *stat_latencies_scsi_nodata; + struct statistic *stat_pending_scsi_write; + struct statistic *stat_pending_scsi_read; + struct statistic *stat_erp; + struct statistic *stat_eh_reset; }; /* FSF request */ @@ -1050,7 +1076,8 @@ struct zfcp_fsf_req { mempool_t *pool; /* used if request was alloacted from emergency pool */ unsigned long long issued; /* request sent time (STCK) */ - struct zfcp_unit *unit; + unsigned long long received; + struct zfcp_unit *unit; }; typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*); diff -Nurp f/drivers/s390/scsi/zfcp_erp.c g/drivers/s390/scsi/zfcp_erp.c --- f/drivers/s390/scsi/zfcp_erp.c 2005-12-14 12:51:26.000000000 +0100 +++ g/drivers/s390/scsi/zfcp_erp.c 2005-12-14 16:01:55.000000000 +0100 @@ -1624,10 +1624,12 @@ zfcp_erp_strategy_check_unit(struct zfcp switch (result) { case ZFCP_ERP_SUCCEEDED : atomic_set(&unit->erp_counter, 0); + statistic_inc(unit->stat_erp, 1); zfcp_erp_unit_unblock(unit); break; case ZFCP_ERP_FAILED : atomic_inc(&unit->erp_counter); + statistic_inc(unit->stat_erp, -1); if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) zfcp_erp_unit_failed(unit); break; @@ -1695,10 +1697,12 @@ zfcp_erp_strategy_check_adapter(struct z switch (result) { case ZFCP_ERP_SUCCEEDED : atomic_set(&adapter->erp_counter, 0); + statistic_inc(adapter->stat_erp, 1); zfcp_erp_adapter_unblock(adapter); break; case ZFCP_ERP_FAILED : atomic_inc(&adapter->erp_counter); + statistic_inc(adapter->stat_erp, -1); if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) zfcp_erp_adapter_failed(adapter); break; diff -Nurp f/drivers/s390/scsi/zfcp_ext.h g/drivers/s390/scsi/zfcp_ext.h --- f/drivers/s390/scsi/zfcp_ext.h 2005-10-28 02:02:08.000000000 +0200 +++ g/drivers/s390/scsi/zfcp_ext.h 2005-12-14 16:01:55.000000000 +0100 @@ -203,4 +203,10 @@ extern void zfcp_scsi_dbf_event_abort(co extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, struct scsi_cmnd *); +/*************************** stat ********************************************/ +extern int zfcp_adapter_statistic_register(struct zfcp_adapter *); +extern int zfcp_adapter_statistic_unregister(struct zfcp_adapter *); +extern int zfcp_unit_statistic_register(struct zfcp_unit *); +extern int zfcp_unit_statistic_unregister(struct zfcp_unit *); + #endif /* ZFCP_EXT_H */ diff -Nurp f/drivers/s390/scsi/zfcp_fsf.c g/drivers/s390/scsi/zfcp_fsf.c --- f/drivers/s390/scsi/zfcp_fsf.c 2005-12-14 12:51:26.000000000 +0100 +++ g/drivers/s390/scsi/zfcp_fsf.c 2005-12-14 16:01:55.000000000 +0100 @@ -219,6 +219,8 @@ zfcp_fsf_req_complete(struct zfcp_fsf_re int retval = 0; int cleanup; + fsf_req->received = get_clock(); + if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { ZFCP_LOG_DEBUG("Status read response received\n"); /* @@ -3471,6 +3473,12 @@ zfcp_fsf_send_fcp_command_task(struct zf unit->fcp_lun, unit->port->wwpn, zfcp_get_busid_by_adapter(adapter)); + if (retval == -ENOMEM) + statistic_inc(unit->stat_sizes_scsi_nomem, + scsi_cmnd->request_bufflen); + if (retval == -EIO) + statistic_inc(unit->stat_sizes_scsi_nofit, + scsi_cmnd->request_bufflen); goto failed_req_create; } @@ -3581,6 +3589,8 @@ zfcp_fsf_send_fcp_command_task(struct zf zfcp_erp_unit_shutdown(unit, 0); retval = -EINVAL; } + statistic_inc(unit->stat_sizes_scsi_nofit, + scsi_cmnd->request_bufflen); goto no_fit; } @@ -3591,6 +3601,13 @@ zfcp_fsf_send_fcp_command_task(struct zf ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + if (scsi_cmnd->sc_data_direction == DMA_FROM_DEVICE) + statistic_inc(unit->stat_pending_scsi_read, + atomic_inc_return(&unit->read_num)); + else if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) + statistic_inc(unit->stat_pending_scsi_write, + atomic_inc_return(&unit->write_num)); + /* * start QDIO request for this FSF request * covered by an SBALE) @@ -3613,6 +3630,11 @@ zfcp_fsf_send_fcp_command_task(struct zf goto success; send_failed: + if (scsi_cmnd->sc_data_direction == DMA_FROM_DEVICE) + atomic_dec(&unit->read_num); + else if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) + atomic_dec(&unit->write_num); + no_fit: failed_scsi_cmnd: zfcp_unit_put(unit); @@ -3984,9 +4006,32 @@ zfcp_fsf_send_fcp_command_task_handler(s u32 sns_len; char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); unsigned long flags; + struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_unit *unit = fsf_req->unit; + long long unsigned latency; - read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); + statistic_lock(unit->stat_if, flags); + latency = fsf_req->received - fsf_req->issued; + do_div(latency, 1000000); + latency++; + if (fcp_cmnd_iu->wddata == 1) { + statistic_inc_nolock(unit->stat_sizes_scsi_write, + zfcp_get_fcp_dl(fcp_cmnd_iu)); + statistic_inc_nolock(unit->stat_latencies_scsi_write, latency); + atomic_dec(&unit->write_num); + } else if (fcp_cmnd_iu->rddata == 1) { + statistic_inc_nolock(unit->stat_sizes_scsi_read, + zfcp_get_fcp_dl(fcp_cmnd_iu)); + statistic_inc_nolock(unit->stat_latencies_scsi_read, latency); + atomic_dec(&unit->read_num); + } else { + statistic_inc_nolock(unit->stat_sizes_scsi_nodata, + zfcp_get_fcp_dl(fcp_cmnd_iu)); + statistic_inc_nolock(unit->stat_latencies_scsi_nodata, latency); + } + statistic_unlock(unit->stat_if, flags); + + read_lock_irqsave(&adapter->abort_lock, flags); scpnt = (struct scsi_cmnd *) fsf_req->data; if (unlikely(!scpnt)) { ZFCP_LOG_DEBUG @@ -4188,7 +4233,7 @@ zfcp_fsf_send_fcp_command_task_handler(s * Note: scsi_done must not block! */ out: - read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags); + read_unlock_irqrestore(&adapter->abort_lock, flags); return retval; } @@ -4605,10 +4650,14 @@ zfcp_fsf_req_sbal_get(struct zfcp_adapte ZFCP_SBAL_TIMEOUT); if (ret < 0) return ret; - if (!ret) + if (!ret) { + statistic_inc(adapter->stat_qdio_outb_full, 1); return -EIO; - } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) + } + } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) { + statistic_inc(adapter->stat_qdio_outb_full, 1); return -EIO; + } return 0; } @@ -4774,6 +4823,9 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *f * position of first one */ atomic_sub(fsf_req->sbal_number, &req_queue->free_count); + statistic_inc(adapter->stat_qdio_outb, + QDIO_MAX_BUFFERS_PER_Q - + atomic_read(&req_queue->free_count)); ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count)); req_queue->free_index += fsf_req->sbal_number; /* increase */ req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */ diff -Nurp f/drivers/s390/scsi/zfcp_qdio.c g/drivers/s390/scsi/zfcp_qdio.c --- f/drivers/s390/scsi/zfcp_qdio.c 2005-10-28 02:02:08.000000000 +0200 +++ g/drivers/s390/scsi/zfcp_qdio.c 2005-12-14 16:01:55.000000000 +0100 @@ -418,6 +418,7 @@ zfcp_qdio_response_handler(struct ccw_de } else { queue->free_index += count; queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; + statistic_inc(adapter->stat_qdio_inb, count); atomic_set(&queue->free_count, 0); ZFCP_LOG_TRACE("%i buffers enqueued to response " "queue at position %i\n", count, start); @@ -662,6 +663,10 @@ zfcp_qdio_sbals_from_segment(struct zfcp /* get next free SBALE for new piece */ if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) { /* no SBALE left, clean up and leave */ + statistic_inc( + fsf_req->adapter->stat_qdio_outb_full, + atomic_read( + &fsf_req->adapter->request_queue.free_count)); zfcp_qdio_sbals_wipe(fsf_req); return -EINVAL; } diff -Nurp f/drivers/s390/scsi/zfcp_scsi.c g/drivers/s390/scsi/zfcp_scsi.c --- f/drivers/s390/scsi/zfcp_scsi.c 2005-12-14 12:51:26.000000000 +0100 +++ g/drivers/s390/scsi/zfcp_scsi.c 2005-12-14 16:01:55.000000000 +0100 @@ -449,6 +449,16 @@ zfcp_scsi_eh_abort_handler(struct scsi_c ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", scpnt, zfcp_get_busid_by_adapter(adapter)); + if (scpnt->sc_data_direction == DMA_TO_DEVICE) + statistic_inc(unit->stat_sizes_timedout_write, + scpnt->request_bufflen); + else if (scpnt->sc_data_direction == DMA_FROM_DEVICE) + statistic_inc(unit->stat_sizes_timedout_read, + scpnt->request_bufflen); + else + statistic_inc(unit->stat_sizes_timedout_nodata, + scpnt->request_bufflen); + /* avoid race condition between late normal completion and abort */ write_lock_irqsave(&adapter->abort_lock, flags); @@ -538,12 +548,14 @@ zfcp_scsi_eh_device_reset_handler(struct atomic_set_mask (ZFCP_STATUS_UNIT_NOTSUPPUNITRESET, &unit->status); + statistic_inc(unit->stat_eh_reset, -1); /* fall through and try 'target reset' next */ } else { ZFCP_LOG_DEBUG("unit reset succeeded (unit=%p)\n", unit); /* avoid 'target reset' */ retval = SUCCESS; + statistic_inc(unit->stat_eh_reset, 1); goto out; } } @@ -551,9 +563,11 @@ zfcp_scsi_eh_device_reset_handler(struct if (retval) { ZFCP_LOG_DEBUG("target reset failed (unit=%p)\n", unit); retval = FAILED; + statistic_inc(unit->stat_eh_reset, -2); } else { ZFCP_LOG_DEBUG("target reset succeeded (unit=%p)\n", unit); retval = SUCCESS; + statistic_inc(unit->stat_eh_reset, 2); } out: return retval; diff -Nurp f/drivers/s390/scsi/zfcp_stat.c g/drivers/s390/scsi/zfcp_stat.c --- f/drivers/s390/scsi/zfcp_stat.c 1970-01-01 01:00:00.000000000 +0100 +++ g/drivers/s390/scsi/zfcp_stat.c 2005-12-14 16:01:55.000000000 +0100 @@ -0,0 +1,195 @@ +/* + * + * linux/drivers/s390/scsi/zfcp_stat.c + * + * FCP adapter driver for IBM eServer zSeries + * + * Statistics + * + * (C) Copyright IBM Corp. 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define ZFCP_STAT_REVISION "$Revision: 1.9 $" + +#include <linux/statistic.h> +#include <linux/ctype.h> +#include "zfcp_ext.h" + +#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER + +int zfcp_adapter_statistic_register(struct zfcp_adapter *adapter) +{ + int retval = 0; + char name[14]; + + sprintf(name, "zfcp-%s", zfcp_get_busid_by_adapter(adapter)); + statistic_interface_create(&adapter->stat_if, name); + + retval |= + statistic_create(&adapter->stat_qdio_outb_full, adapter->stat_if, + "occurrence_qdio_outb_full", + "sbals_left/incidents"); + statistic_define_value(adapter->stat_qdio_outb_full, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + retval |= statistic_create(&adapter->stat_qdio_outb, adapter->stat_if, + "util_qdio_outb", + "slots-occupied/incidents"); + statistic_define_range(adapter->stat_qdio_outb, + 0, QDIO_MAX_BUFFERS_PER_Q); + + retval |= statistic_create(&adapter->stat_qdio_inb, adapter->stat_if, + "util_qdio_inb", "slots-occupied/incidents"); + statistic_define_range(adapter->stat_qdio_inb, + 0, QDIO_MAX_BUFFERS_PER_Q); + + retval |= + statistic_create(&adapter->stat_low_mem_scsi, adapter->stat_if, + "occurrence_low_mem_scsi", "-/incidents"); + statistic_define_value(adapter->stat_low_mem_scsi, STATISTIC_RANGE_MIN, + STATISTIC_RANGE_MAX, STATISTIC_DEF_MODE_INC); + + retval |= statistic_create(&adapter->stat_erp, adapter->stat_if, + "occurrence_erp", "results/incidents"); + statistic_define_value(adapter->stat_erp, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + return retval; +} + +int zfcp_adapter_statistic_unregister(struct zfcp_adapter *adapter) +{ + return statistic_interface_remove(&adapter->stat_if); +} + +int zfcp_unit_statistic_register(struct zfcp_unit *unit) +{ + int retval = 0; + char name[64]; + + atomic_set(&unit->read_num, 0); + atomic_set(&unit->write_num, 0); + + sprintf(name, "zfcp-%s-0x%016Lx-0x%016Lx", + zfcp_get_busid_by_unit(unit), unit->port->wwpn, unit->fcp_lun); + statistic_interface_create(&unit->stat_if, name); + + retval |= statistic_create(&unit->stat_sizes_scsi_write, unit->stat_if, + "request_sizes_scsi_write", + "bytes/incidents"); + statistic_define_list(unit->stat_sizes_scsi_write, 0, + STATISTIC_RANGE_MAX, 256); + + retval |= statistic_create(&unit->stat_sizes_scsi_read, unit->stat_if, + "request_sizes_scsi_read", + "bytes/incidents"); + statistic_define_list(unit->stat_sizes_scsi_read, 0, + STATISTIC_RANGE_MAX, 256); + + retval |= statistic_create(&unit->stat_sizes_scsi_nodata, unit->stat_if, + "request_sizes_scsi_nodata", + "bytes/incidents"); + statistic_define_value(unit->stat_sizes_scsi_nodata, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + retval |= statistic_create(&unit->stat_sizes_scsi_nofit, unit->stat_if, + "request_sizes_scsi_nofit", + "bytes/incidents"); + statistic_define_list(unit->stat_sizes_scsi_nofit, 0, + STATISTIC_RANGE_MAX, 256); + + retval |= statistic_create(&unit->stat_sizes_scsi_nomem, unit->stat_if, + "request_sizes_scsi_nomem", + "bytes/incidents"); + statistic_define_value(unit->stat_sizes_scsi_nomem, STATISTIC_RANGE_MIN, + STATISTIC_RANGE_MAX, STATISTIC_DEF_MODE_INC); + + retval |= + statistic_create(&unit->stat_sizes_timedout_write, unit->stat_if, + "request_sizes_timedout_write", "bytes/incidents"); + statistic_define_value(unit->stat_sizes_timedout_write, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + retval |= + statistic_create(&unit->stat_sizes_timedout_read, unit->stat_if, + "request_sizes_timedout_read", "bytes/incidents"); + statistic_define_value(unit->stat_sizes_timedout_read, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + retval |= + statistic_create(&unit->stat_sizes_timedout_nodata, unit->stat_if, + "request_sizes_timedout_nodata", + "bytes/incidents"); + statistic_define_value(unit->stat_sizes_timedout_nodata, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + retval |= + statistic_create(&unit->stat_latencies_scsi_write, unit->stat_if, + "latencies_scsi_write", "milliseconds/incidents"); + statistic_define_array(unit->stat_latencies_scsi_write, 0, 1024, 1, + STATISTIC_DEF_SCALE_LOG2); + + retval |= + statistic_create(&unit->stat_latencies_scsi_read, unit->stat_if, + "latencies_scsi_read", "milliseconds/incidents"); + statistic_define_array(unit->stat_latencies_scsi_read, 0, 1024, 1, + STATISTIC_DEF_SCALE_LOG2); + + retval |= + statistic_create(&unit->stat_latencies_scsi_nodata, unit->stat_if, + "latencies_scsi_nodata", "milliseconds/incidents"); + statistic_define_array(unit->stat_latencies_scsi_nodata, 0, 1024, 1, + STATISTIC_DEF_SCALE_LOG2); + + retval |= + statistic_create(&unit->stat_pending_scsi_write, unit->stat_if, + "pending_scsi_write", "commands/incidents"); + statistic_define_range(unit->stat_pending_scsi_write, 0, + STATISTIC_RANGE_MAX); + + retval |= statistic_create(&unit->stat_pending_scsi_read, unit->stat_if, + "pending_scsi_read", "commands/incidents"); + statistic_define_range(unit->stat_pending_scsi_read, 0, + STATISTIC_RANGE_MAX); + + retval |= statistic_create(&unit->stat_erp, unit->stat_if, + "occurrence_erp", "results/incidents"); + statistic_define_value(unit->stat_erp, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + retval |= statistic_create(&unit->stat_eh_reset, unit->stat_if, + "occurrence_eh_reset", "results/incidents"); + statistic_define_value(unit->stat_eh_reset, + STATISTIC_RANGE_MIN, STATISTIC_RANGE_MAX, + STATISTIC_DEF_MODE_INC); + + return retval; +} + +int zfcp_unit_statistic_unregister(struct zfcp_unit *unit) +{ + return statistic_interface_remove(&unit->stat_if); +} + +#undef ZFCP_LOG_AREA - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html