cregit-Linux how code gets into the kernel

Release 4.7 drivers/s390/cio/ccwreq.c

Directory: drivers/s390/cio
/*
 *  Handling of internal CCW device requests.
 *
 *    Copyright IBM Corp. 2009, 2011
 *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
 */


#define KMSG_COMPONENT "cio"

#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/types.h>
#include <linux/err.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>

#include "io_sch.h"
#include "cio.h"
#include "device.h"
#include "cio_debug.h"

/**
 * lpm_adjust - adjust path mask
 * @lpm: path mask to adjust
 * @mask: mask of available paths
 *
 * Shift @lpm right until @lpm and @mask have at least one bit in common or
 * until @lpm is zero. Return the resulting lpm.
 */

int lpm_adjust(int lpm, int mask) { while (lpm && ((lpm & mask) == 0)) lpm >>= 1; return lpm; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter32100.00%1100.00%
Total32100.00%1100.00%

/* * Adjust path mask to use next path and reset retry count. Return resulting * path mask. */
static u16 ccwreq_next_path(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; if (!req->singlepath) { req->mask = 0; goto out; } req->retries = req->maxretries; req->mask = lpm_adjust(req->mask >> 1, req->lpm); out: return req->mask; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter5271.23%133.33%
sebastian ottsebastian ott2128.77%266.67%
Total73100.00%3100.00%

/* * Clean up device state and report to callback. */
static void ccwreq_stop(struct ccw_device *cdev, int rc) { struct ccw_request *req = &cdev->private->req; if (req->done) return; req->done = 1; ccw_device_set_timeout(cdev, 0); memset(&cdev->private->irb, 0, sizeof(struct irb)); if (rc && rc != -ENODEV && req->drc) rc = req->drc; req->callback(cdev, req->data, rc); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter96100.00%1100.00%
Total96100.00%1100.00%

/* * (Re-)Start the operation until retries and paths are exhausted. */
static void ccwreq_do(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; struct subchannel *sch = to_subchannel(cdev->dev.parent); struct ccw1 *cp = req->cp; int rc = -EACCES; while (req->mask) { if (req->retries-- == 0) { /* Retries exhausted, try next path. */ ccwreq_next_path(cdev); continue; } /* Perform start function. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); rc = cio_start(sch, cp, (u8) req->mask); if (rc == 0) { /* I/O started successfully. */ ccw_device_set_timeout(cdev, req->timeout); return; } if (rc == -ENODEV) { /* Permanent device error. */ break; } if (rc == -EACCES) { /* Permant path error. */ ccwreq_next_path(cdev); continue; } /* Temporary improper status. */ rc = cio_clear(sch); if (rc) break; return; } ccwreq_stop(cdev, rc); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter180100.00%2100.00%
Total180100.00%2100.00%

/** * ccw_request_start - perform I/O request * @cdev: ccw device * * Perform the I/O request specified by cdev->req. */
void ccw_request_start(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; if (req->singlepath) { /* Try all paths twice to counter link flapping. */ req->mask = 0x8080; } else req->mask = req->lpm; req->retries = req->maxretries; req->mask = lpm_adjust(req->mask, req->lpm); req->drc = 0; req->done = 0; req->cancel = 0; if (!req->mask) goto out_nopath; ccwreq_do(cdev); return; out_nopath: ccwreq_stop(cdev, -EACCES); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter9684.96%266.67%
sebastian ottsebastian ott1715.04%133.33%
Total113100.00%3100.00%

/** * ccw_request_cancel - cancel running I/O request * @cdev: ccw device * * Cancel the I/O request specified by cdev->req. Return non-zero if request * has already finished, zero otherwise. */
int ccw_request_cancel(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); struct ccw_request *req = &cdev->private->req; int rc; if (req->done) return 1; req->cancel = 1; rc = cio_clear(sch); if (rc) ccwreq_stop(cdev, rc); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter75100.00%1100.00%
Total75100.00%1100.00%

/* * Return the status of the internal I/O started on the specified ccw device. * Perform BASIC SENSE if required. */
static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) { struct irb *irb = &cdev->private->irb; struct cmd_scsw *scsw = &irb->scsw.cmd; enum uc_todo todo; /* Perform BASIC SENSE if needed. */ if (ccw_device_accumulate_and_sense(cdev, lcirb)) return IO_RUNNING; /* Check for halt/clear interrupt. */ if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) return IO_KILLED; /* Check for path error. */ if (scsw->cc == 3 || scsw->pno) return IO_PATH_ERROR; /* Handle BASIC SENSE data. */ if (irb->esw.esw0.erw.cons) { CIO_TRACE_EVENT(2, "sensedata"); CIO_HEX_EVENT(2, &cdev->private->dev_id, sizeof(struct ccw_dev_id)); CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT); /* Check for command reject. */ if (irb->ecw[0] & SNS0_CMD_REJECT) return IO_REJECTED; /* Ask the driver what to do */ if (cdev->drv && cdev->drv->uc_handler) { todo = cdev->drv->uc_handler(cdev, lcirb); CIO_TRACE_EVENT(2, "uc_response"); CIO_HEX_EVENT(2, &todo, sizeof(todo)); switch (todo) { case UC_TODO_RETRY: return IO_STATUS_ERROR; case UC_TODO_RETRY_ON_NEW_PATH: return IO_PATH_ERROR; case UC_TODO_STOP: return IO_REJECTED; default: return IO_STATUS_ERROR; } } /* Assume that unexpected SENSE data implies an error. */ return IO_STATUS_ERROR; } /* Check for channel errors. */ if (scsw->cstat != 0) return IO_STATUS_ERROR; /* Check for device errors. */ if (scsw->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) return IO_STATUS_ERROR; /* Check for final state. */ if (!(scsw->dstat & DEV_STAT_DEV_END)) return IO_RUNNING; /* Check for other improper status. */ if (scsw->cc == 1 && (scsw->stctl & SCSW_STCTL_ALERT_STATUS)) return IO_STATUS_ERROR; return IO_DONE; }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter22874.03%133.33%
michael ernstmichael ernst8025.97%266.67%
Total308100.00%3100.00%

/* * Log ccw request status. */
static void ccwreq_log_status(struct ccw_device *cdev, enum io_status status) { struct ccw_request *req = &cdev->private->req; struct { struct ccw_dev_id dev_id; u16 retries; u8 lpm; u8 status; } __attribute__ ((packed)) data; data.dev_id = cdev->private->dev_id; data.retries = req->retries; data.lpm = (u8) req->mask; data.status = (u8) status; CIO_TRACE_EVENT(2, "reqstat"); CIO_HEX_EVENT(2, &data, sizeof(data)); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter109100.00%2100.00%
Total109100.00%2100.00%

/** * ccw_request_handler - interrupt handler for I/O request procedure. * @cdev: ccw device * * Handle interrupt during I/O request procedure. */
void ccw_request_handler(struct ccw_device *cdev) { struct irb *irb = this_cpu_ptr(&cio_irb); struct ccw_request *req = &cdev->private->req; enum io_status status; int rc = -EOPNOTSUPP; /* Check status of I/O request. */ status = ccwreq_status(cdev, irb); if (req->filter) status = req->filter(cdev, req->data, irb, status); if (status != IO_RUNNING) ccw_device_set_timeout(cdev, 0); if (status != IO_DONE && status != IO_RUNNING) ccwreq_log_status(cdev, status); switch (status) { case IO_DONE: break; case IO_RUNNING: return; case IO_REJECTED: goto err; case IO_PATH_ERROR: goto out_next_path; case IO_STATUS_ERROR: goto out_restart; case IO_KILLED: /* Check if request was cancelled on purpose. */ if (req->cancel) { rc = -EIO; goto err; } goto out_restart; } /* Check back with request initiator. */ if (!req->check) goto out; switch (req->check(cdev, req->data)) { case 0: break; case -EAGAIN: goto out_restart; case -EACCES: goto out_next_path; default: goto err; } out: ccwreq_stop(cdev, 0); return; out_next_path: /* Try next path and restart I/O. */ if (!ccwreq_next_path(cdev)) { rc = -EACCES; goto err; } out_restart: /* Restart. */ ccwreq_do(cdev); return; err: ccwreq_stop(cdev, rc); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter24795.74%125.00%
heiko carstensheiko carstens62.33%125.00%
martin schwidefskymartin schwidefsky31.16%125.00%
christoph lameterchristoph lameter20.78%125.00%
Total258100.00%4100.00%

/** * ccw_request_timeout - timeout handler for I/O request procedure * @cdev: ccw device * * Handle timeout during I/O request procedure. */
void ccw_request_timeout(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); struct ccw_request *req = &cdev->private->req; int rc = -ENODEV, chp; if (cio_update_schib(sch)) goto err; for (chp = 0; chp < 8; chp++) { if ((0x80 >> chp) & sch->schib.pmcw.lpum) pr_warn("%s: No interrupt was received within %lus (CS=%02x, DS=%02x, CHPID=%x.%02x)\n", dev_name(&cdev->dev), req->timeout / HZ, scsw_cstat(&sch->schib.scsw), scsw_dstat(&sch->schib.scsw), sch->schid.cssid, sch->schib.pmcw.chpid[chp]); } if (!ccwreq_next_path(cdev)) { /* set the final return code for this request */ req->drc = -ETIME; } rc = cio_clear(sch); if (rc) goto err; return; err: ccwreq_stop(cdev, rc); }

Contributors

PersonTokensPropCommitsCommitProp
sebastian ottsebastian ott10054.64%133.33%
peter oberparleiterpeter oberparleiter8144.26%133.33%
joe perchesjoe perches21.09%133.33%
Total183100.00%3100.00%

/** * ccw_request_notoper - notoper handler for I/O request procedure * @cdev: ccw device * * Handle notoper during I/O request procedure. */
void ccw_request_notoper(struct ccw_device *cdev) { ccwreq_stop(cdev, -ENODEV); }

Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter18100.00%1100.00%
Total18100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
peter oberparleiterpeter oberparleiter124883.65%218.18%
sebastian ottsebastian ott15110.12%327.27%
michael ernstmichael ernst805.36%218.18%
heiko carstensheiko carstens60.40%19.09%
martin schwidefskymartin schwidefsky30.20%19.09%
joe perchesjoe perches20.13%19.09%
christoph lameterchristoph lameter20.13%19.09%
Total1492100.00%11100.00%
Directory: drivers/s390/cio
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}