device_pgid.c
来自「linux 内核源代码」· C语言 代码 · 共 597 行 · 第 1/2 页
C
597 行
/* * drivers/s390/cio/device_pgid.c * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) * * Path Group ID functions. */#include <linux/module.h>#include <linux/init.h>#include <asm/ccwdev.h>#include <asm/cio.h>#include <asm/delay.h>#include <asm/lowcore.h>#include "cio.h"#include "cio_debug.h"#include "css.h"#include "device.h"#include "ioasm.h"/* * Helper function called from interrupt context to decide whether an * operation should be tried again. */static int __ccw_device_should_retry(struct scsw *scsw){ /* CC is only valid if start function bit is set. */ if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1) return 1; /* No more activity. For sense and set PGID we stubbornly try again. */ if (!scsw->actl) return 1; return 0;}/* * Start Sense Path Group ID helper function. Used in ccw_device_recog * and ccw_device_sense_pgid. */static int__ccw_device_sense_pgid_start(struct ccw_device *cdev){ struct subchannel *sch; struct ccw1 *ccw; int ret; int i; sch = to_subchannel(cdev->dev.parent); /* Return if we already checked on all paths. */ if (cdev->private->imask == 0) return (sch->lpm == 0) ? -ENODEV : -EACCES; i = 8 - ffs(cdev->private->imask); /* Setup sense path group id channel program. */ ccw = cdev->private->iccws; ccw->cmd_code = CCW_CMD_SENSE_PGID; ccw->count = sizeof (struct pgid); ccw->flags = CCW_FLAG_SLI; /* Reset device status. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); /* Try on every path. */ ret = -ENODEV; while (cdev->private->imask != 0) { /* Try every path multiple times. */ ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); if (cdev->private->iretry > 0) { cdev->private->iretry--; /* Reset internal retry indication. */ cdev->private->flags.intretry = 0; ret = cio_start (sch, cdev->private->iccws, cdev->private->imask); /* ret is 0, -EBUSY, -EACCES or -ENODEV */ if (ret != -EACCES) return ret; CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not " "operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); } cdev->private->imask >>= 1; cdev->private->iretry = 5; i++; } return ret;}voidccw_device_sense_pgid_start(struct ccw_device *cdev){ int ret; /* Set a timeout of 60s */ ccw_device_set_timeout(cdev, 60*HZ); cdev->private->state = DEV_STATE_SENSE_PGID; cdev->private->imask = 0x80; cdev->private->iretry = 5; memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid)); ret = __ccw_device_sense_pgid_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_pgid_done(cdev, ret);}/* * Called from interrupt context to check if a valid answer * to Sense Path Group ID was received. */static int__ccw_device_check_sense_pgid(struct ccw_device *cdev){ struct subchannel *sch; struct irb *irb; int i; sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Sense PGID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; return -EAGAIN; } return -ETIME; } if (irb->esw.esw0.erw.cons && (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { /* * If the device doesn't support the Sense Path Group ID * command further retries wouldn't help ... */ return -EOPNOTSUPP; } if (irb->esw.esw0.erw.cons) { CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, " "lpum %02X, cnt %02d, sns : " "%02X%02X%02X%02X %02X%02X%02X%02X ...\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, irb->esw.esw0.sublog.lpum, irb->esw.esw0.erw.scnt, irb->ecw[0], irb->ecw[1], irb->ecw[2], irb->ecw[3], irb->ecw[4], irb->ecw[5], irb->ecw[6], irb->ecw[7]); return -EAGAIN; } if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, sch->orb.lpm); return -EACCES; } i = 8 - ffs(cdev->private->imask); if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x " "is reserved by someone else\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); return -EUSERS; } return 0;}/* * Got interrupt for Sense Path Group ID. */voidccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event){ struct subchannel *sch; struct irb *irb; int ret; irb = (struct irb *) __LC_IRB; if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) { ret = __ccw_device_sense_pgid_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_pgid_done(cdev, ret); } return; } if (ccw_device_accumulate_and_sense(cdev, irb) != 0) return; sch = to_subchannel(cdev->dev.parent); ret = __ccw_device_check_sense_pgid(cdev); memset(&cdev->private->irb, 0, sizeof(struct irb)); switch (ret) { /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ case -EOPNOTSUPP: /* Sense Path Group ID not supported */ ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP); break; case -ETIME: /* Sense path group id stopped by timeout. */ ccw_device_sense_pgid_done(cdev, -ETIME); break; case -EACCES: /* channel is not operational. */ sch->lpm &= ~cdev->private->imask; /* Fall through. */ case 0: /* Sense Path Group ID successful. */ cdev->private->imask >>= 1; cdev->private->iretry = 5; /* Fall through. */ case -EAGAIN: /* Try again. */ ret = __ccw_device_sense_pgid_start(cdev); if (ret != 0 && ret != -EBUSY) ccw_device_sense_pgid_done(cdev, ret); break; case -EUSERS: /* device is reserved for someone else. */ ccw_device_sense_pgid_done(cdev, -EUSERS); break; }}/* * Path Group ID helper function. */static int__ccw_device_do_pgid(struct ccw_device *cdev, __u8 func){ struct subchannel *sch; struct ccw1 *ccw; int ret; sch = to_subchannel(cdev->dev.parent); /* Setup sense path group id channel program. */ cdev->private->pgid[0].inf.fc = func; ccw = cdev->private->iccws; if (!cdev->private->flags.pgid_single) { cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH; ccw->cmd_code = CCW_CMD_SUSPEND_RECONN; ccw->cda = 0; ccw->count = 0; ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC; ccw++; } else cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH; ccw->cmd_code = CCW_CMD_SET_PGID; ccw->cda = (__u32) __pa (&cdev->private->pgid[0]); ccw->count = sizeof (struct pgid); ccw->flags = CCW_FLAG_SLI; /* Reset device status. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); /* Try multiple times. */ ret = -EACCES; if (cdev->private->iretry > 0) { cdev->private->iretry--; /* Reset internal retry indication. */ cdev->private->flags.intretry = 0; ret = cio_start (sch, cdev->private->iccws, cdev->private->imask); /* We expect an interrupt in case of success or busy * indication. */ if ((ret == 0) || (ret == -EBUSY)) return ret; } /* PGID command failed on this path. */ CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " "0.%x.%04x, lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, cdev->private->imask); return ret;}/* * Helper function to send a nop ccw down a path. */static int __ccw_device_do_nop(struct ccw_device *cdev){ struct subchannel *sch; struct ccw1 *ccw; int ret; sch = to_subchannel(cdev->dev.parent); /* Setup nop channel program. */ ccw = cdev->private->iccws; ccw->cmd_code = CCW_CMD_NOOP; ccw->cda = 0; ccw->count = 0; ccw->flags = CCW_FLAG_SLI; /* Reset device status. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?