Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * zfcp device driver
0004  *
0005  * Functions to handle diagnostics.
0006  *
0007  * Copyright IBM Corp. 2018
0008  */
0009 
0010 #include <linux/spinlock.h>
0011 #include <linux/jiffies.h>
0012 #include <linux/string.h>
0013 #include <linux/errno.h>
0014 #include <linux/slab.h>
0015 
0016 #include "zfcp_diag.h"
0017 #include "zfcp_ext.h"
0018 #include "zfcp_def.h"
0019 
0020 static DECLARE_WAIT_QUEUE_HEAD(__zfcp_diag_publish_wait);
0021 
0022 /**
0023  * zfcp_diag_adapter_setup() - Setup storage for adapter diagnostics.
0024  * @adapter: the adapter to setup diagnostics for.
0025  *
0026  * Creates the data-structures to store the diagnostics for an adapter. This
0027  * overwrites whatever was stored before at &zfcp_adapter->diagnostics!
0028  *
0029  * Return:
0030  * * 0       - Everyting is OK
0031  * * -ENOMEM - Could not allocate all/parts of the data-structures;
0032  *         &zfcp_adapter->diagnostics remains unchanged
0033  */
0034 int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter)
0035 {
0036     struct zfcp_diag_adapter *diag;
0037     struct zfcp_diag_header *hdr;
0038 
0039     diag = kzalloc(sizeof(*diag), GFP_KERNEL);
0040     if (diag == NULL)
0041         return -ENOMEM;
0042 
0043     diag->max_age = (5 * 1000); /* default value: 5 s */
0044 
0045     /* setup header for port_data */
0046     hdr = &diag->port_data.header;
0047 
0048     spin_lock_init(&hdr->access_lock);
0049     hdr->buffer = &diag->port_data.data;
0050     hdr->buffer_size = sizeof(diag->port_data.data);
0051     /* set the timestamp so that the first test on age will always fail */
0052     hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age);
0053 
0054     /* setup header for config_data */
0055     hdr = &diag->config_data.header;
0056 
0057     spin_lock_init(&hdr->access_lock);
0058     hdr->buffer = &diag->config_data.data;
0059     hdr->buffer_size = sizeof(diag->config_data.data);
0060     /* set the timestamp so that the first test on age will always fail */
0061     hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age);
0062 
0063     adapter->diagnostics = diag;
0064     return 0;
0065 }
0066 
0067 /**
0068  * zfcp_diag_adapter_free() - Frees all adapter diagnostics allocations.
0069  * @adapter: the adapter whose diagnostic structures should be freed.
0070  *
0071  * Frees all data-structures in the given adapter that store diagnostics
0072  * information. Can savely be called with partially setup diagnostics.
0073  */
0074 void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter)
0075 {
0076     kfree(adapter->diagnostics);
0077     adapter->diagnostics = NULL;
0078 }
0079 
0080 /**
0081  * zfcp_diag_update_xdata() - Update a diagnostics buffer.
0082  * @hdr: the meta data to update.
0083  * @data: data to use for the update.
0084  * @incomplete: flag stating whether the data in @data is incomplete.
0085  */
0086 void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr,
0087                 const void *const data, const bool incomplete)
0088 {
0089     const unsigned long capture_timestamp = jiffies;
0090     unsigned long flags;
0091 
0092     spin_lock_irqsave(&hdr->access_lock, flags);
0093 
0094     /* make sure we never go into the past with an update */
0095     if (!time_after_eq(capture_timestamp, hdr->timestamp))
0096         goto out;
0097 
0098     hdr->timestamp = capture_timestamp;
0099     hdr->incomplete = incomplete;
0100     memcpy(hdr->buffer, data, hdr->buffer_size);
0101 out:
0102     spin_unlock_irqrestore(&hdr->access_lock, flags);
0103 }
0104 
0105 /**
0106  * zfcp_diag_update_port_data_buffer() - Implementation of
0107  *                   &typedef zfcp_diag_update_buffer_func
0108  *                   to collect and update Port Data.
0109  * @adapter: Adapter to collect Port Data from.
0110  *
0111  * This call is SYNCHRONOUS ! It blocks till the respective command has
0112  * finished completely, or has failed in some way.
0113  *
0114  * Return:
0115  * * 0      - Successfully retrieved new Diagnostics and Updated the buffer;
0116  *        this also includes cases where data was retrieved, but
0117  *        incomplete; you'll have to check the flag ``incomplete``
0118  *        of &struct zfcp_diag_header.
0119  * * see zfcp_fsf_exchange_port_data_sync() for possible error-codes (
0120  *   excluding -EAGAIN)
0121  */
0122 int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter)
0123 {
0124     int rc;
0125 
0126     rc = zfcp_fsf_exchange_port_data_sync(adapter->qdio, NULL);
0127     if (rc == -EAGAIN)
0128         rc = 0; /* signaling incomplete via struct zfcp_diag_header */
0129 
0130     /* buffer-data was updated in zfcp_fsf_exchange_port_data_handler() */
0131 
0132     return rc;
0133 }
0134 
0135 /**
0136  * zfcp_diag_update_config_data_buffer() - Implementation of
0137  *                     &typedef zfcp_diag_update_buffer_func
0138  *                     to collect and update Config Data.
0139  * @adapter: Adapter to collect Config Data from.
0140  *
0141  * This call is SYNCHRONOUS ! It blocks till the respective command has
0142  * finished completely, or has failed in some way.
0143  *
0144  * Return:
0145  * * 0      - Successfully retrieved new Diagnostics and Updated the buffer;
0146  *        this also includes cases where data was retrieved, but
0147  *        incomplete; you'll have to check the flag ``incomplete``
0148  *        of &struct zfcp_diag_header.
0149  * * see zfcp_fsf_exchange_config_data_sync() for possible error-codes (
0150  *   excluding -EAGAIN)
0151  */
0152 int zfcp_diag_update_config_data_buffer(struct zfcp_adapter *const adapter)
0153 {
0154     int rc;
0155 
0156     rc = zfcp_fsf_exchange_config_data_sync(adapter->qdio, NULL);
0157     if (rc == -EAGAIN)
0158         rc = 0; /* signaling incomplete via struct zfcp_diag_header */
0159 
0160     /* buffer-data was updated in zfcp_fsf_exchange_config_data_handler() */
0161 
0162     return rc;
0163 }
0164 
0165 static int __zfcp_diag_update_buffer(struct zfcp_adapter *const adapter,
0166                      struct zfcp_diag_header *const hdr,
0167                      zfcp_diag_update_buffer_func buffer_update,
0168                      unsigned long *const flags)
0169     __must_hold(hdr->access_lock)
0170 {
0171     int rc;
0172 
0173     if (hdr->updating == 1) {
0174         rc = wait_event_interruptible_lock_irq(__zfcp_diag_publish_wait,
0175                                hdr->updating == 0,
0176                                hdr->access_lock);
0177         rc = (rc == 0 ? -EAGAIN : -EINTR);
0178     } else {
0179         hdr->updating = 1;
0180         spin_unlock_irqrestore(&hdr->access_lock, *flags);
0181 
0182         /* unlocked, because update function sleeps */
0183         rc = buffer_update(adapter);
0184 
0185         spin_lock_irqsave(&hdr->access_lock, *flags);
0186         hdr->updating = 0;
0187 
0188         /*
0189          * every thread waiting here went via an interruptible wait,
0190          * so its fine to only wake those
0191          */
0192         wake_up_interruptible_all(&__zfcp_diag_publish_wait);
0193     }
0194 
0195     return rc;
0196 }
0197 
0198 static bool
0199 __zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_adapter *const diag,
0200                     const struct zfcp_diag_header *const hdr)
0201     __must_hold(hdr->access_lock)
0202 {
0203     const unsigned long now = jiffies;
0204 
0205     /*
0206      * Should not happen (data is from the future).. if it does, still
0207      * signal that it needs refresh
0208      */
0209     if (!time_after_eq(now, hdr->timestamp))
0210         return false;
0211 
0212     if (jiffies_to_msecs(now - hdr->timestamp) >= diag->max_age)
0213         return false;
0214 
0215     return true;
0216 }
0217 
0218 /**
0219  * zfcp_diag_update_buffer_limited() - Collect diagnostics and update a
0220  *                     diagnostics buffer rate limited.
0221  * @adapter: Adapter to collect the diagnostics from.
0222  * @hdr: buffer-header for which to update with the collected diagnostics.
0223  * @buffer_update: Specific implementation for collecting and updating.
0224  *
0225  * This function will cause an update of the given @hdr by calling the also
0226  * given @buffer_update function. If called by multiple sources at the same
0227  * time, it will synchornize the update by only allowing one source to call
0228  * @buffer_update and the others to wait for that source to complete instead
0229  * (the wait is interruptible).
0230  *
0231  * Additionally this version is rate-limited and will only exit if either the
0232  * buffer is fresh enough (within the limit) - it will do nothing if the buffer
0233  * is fresh enough to begin with -, or if the source/thread that started this
0234  * update is the one that made the update (to prevent endless loops).
0235  *
0236  * Return:
0237  * * 0      - If the update was successfully published and/or the buffer is
0238  *        fresh enough
0239  * * -EINTR - If the thread went into the wait-state and was interrupted
0240  * * whatever @buffer_update returns
0241  */
0242 int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter,
0243                     struct zfcp_diag_header *const hdr,
0244                     zfcp_diag_update_buffer_func buffer_update)
0245 {
0246     unsigned long flags;
0247     int rc;
0248 
0249     spin_lock_irqsave(&hdr->access_lock, flags);
0250 
0251     for (rc = 0;
0252          !__zfcp_diag_test_buffer_age_isfresh(adapter->diagnostics, hdr);
0253          rc = 0) {
0254         rc = __zfcp_diag_update_buffer(adapter, hdr, buffer_update,
0255                            &flags);
0256         if (rc != -EAGAIN)
0257             break;
0258     }
0259 
0260     spin_unlock_irqrestore(&hdr->access_lock, flags);
0261 
0262     return rc;
0263 }