device_pgid.c
来自「linux 内核源代码」· C语言 代码 · 共 597 行 · 第 1/2 页
C
597 行
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; } /* nop command failed on this path. */ CIO_MSG_EVENT(2, "NOP - 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;}/* * Called from interrupt context to check if a valid answer * to Set Path Group ID was received. */static int__ccw_device_check_pgid(struct ccw_device *cdev){ struct subchannel *sch; struct irb *irb; sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Set PGID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; return -EAGAIN; } return -ETIME; } if (irb->esw.esw0.erw.cons) { if (irb->ecw[0] & SNS0_CMD_REJECT) return -EOPNOTSUPP; /* Hmm, whatever happened, try again. */ CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, " "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.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, "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 -EACCES; } return 0;}/* * Called from interrupt context to check the path status after a nop has * been send. */static int __ccw_device_check_nop(struct ccw_device *cdev){ struct subchannel *sch; struct irb *irb; sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry NOP if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; return -EAGAIN; } return -ETIME; } if (irb->scsw.cc == 3) { CIO_MSG_EVENT(2, "NOP - 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 -EACCES; } return 0;}static void__ccw_device_verify_start(struct ccw_device *cdev){ struct subchannel *sch; __u8 func; int ret; sch = to_subchannel(cdev->dev.parent); /* Repeat for all paths. */ for (; cdev->private->imask; cdev->private->imask >>= 1, cdev->private->iretry = 5) { if ((cdev->private->imask & sch->schib.pmcw.pam) == 0) /* Path not available, try next. */ continue; if (cdev->private->options.pgroup) { if (sch->opm & cdev->private->imask) func = SPID_FUNC_ESTABLISH; else func = SPID_FUNC_RESIGN; ret = __ccw_device_do_pgid(cdev, func); } else ret = __ccw_device_do_nop(cdev); /* We expect an interrupt in case of success or busy * indication. */ if (ret == 0 || ret == -EBUSY) return; /* Permanent path failure, try next. */ } /* Done with all paths. */ ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);} /* * Got interrupt for Set Path Group ID. */voidccw_device_verify_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)) __ccw_device_verify_start(cdev); return; } if (ccw_device_accumulate_and_sense(cdev, irb) != 0) return; sch = to_subchannel(cdev->dev.parent); if (cdev->private->options.pgroup) ret = __ccw_device_check_pgid(cdev); else ret = __ccw_device_check_nop(cdev); memset(&cdev->private->irb, 0, sizeof(struct irb)); switch (ret) { /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ case 0: /* Path verification ccw finished successfully, update lpm. */ sch->vpm |= sch->opm & cdev->private->imask; /* Go on with next path. */ cdev->private->imask >>= 1; cdev->private->iretry = 5; __ccw_device_verify_start(cdev); break; case -EOPNOTSUPP: /* * One of those strange devices which claim to be able * to do multipathing but not for Set Path Group ID. */ if (cdev->private->flags.pgid_single) cdev->private->options.pgroup = 0; else cdev->private->flags.pgid_single = 1; /* Retry */ sch->vpm = 0; cdev->private->imask = 0x80; cdev->private->iretry = 5; /* fall through. */ case -EAGAIN: /* Try again. */ __ccw_device_verify_start(cdev); break; case -ETIME: /* Set path group id stopped by timeout. */ ccw_device_verify_done(cdev, -ETIME); break; case -EACCES: /* channel is not operational. */ cdev->private->imask >>= 1; cdev->private->iretry = 5; __ccw_device_verify_start(cdev); break; }}voidccw_device_verify_start(struct ccw_device *cdev){ struct subchannel *sch = to_subchannel(cdev->dev.parent); cdev->private->flags.pgid_single = 0; cdev->private->imask = 0x80; cdev->private->iretry = 5; /* Start with empty vpm. */ sch->vpm = 0; /* Get current pam. */ if (stsch(sch->schid, &sch->schib)) { ccw_device_verify_done(cdev, -ENODEV); return; } /* After 60s path verification is considered to have failed. */ ccw_device_set_timeout(cdev, 60*HZ); __ccw_device_verify_start(cdev);}static void__ccw_device_disband_start(struct ccw_device *cdev){ struct subchannel *sch; int ret; sch = to_subchannel(cdev->dev.parent); while (cdev->private->imask != 0) { if (sch->lpm & cdev->private->imask) { ret = __ccw_device_do_pgid(cdev, SPID_FUNC_DISBAND); if (ret == 0) return; } cdev->private->iretry = 5; cdev->private->imask >>= 1; } ccw_device_disband_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);}/* * Got interrupt for Unset Path Group ID. */voidccw_device_disband_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)) __ccw_device_disband_start(cdev); return; } if (ccw_device_accumulate_and_sense(cdev, irb) != 0) return; sch = to_subchannel(cdev->dev.parent); ret = __ccw_device_check_pgid(cdev); memset(&cdev->private->irb, 0, sizeof(struct irb)); switch (ret) { /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ case 0: /* disband successful. */ ccw_device_disband_done(cdev, ret); break; case -EOPNOTSUPP: /* * One of those strange devices which claim to be able * to do multipathing but not for Unset Path Group ID. */ cdev->private->flags.pgid_single = 1; /* fall through. */ case -EAGAIN: /* Try again. */ __ccw_device_disband_start(cdev); break; case -ETIME: /* Set path group id stopped by timeout. */ ccw_device_disband_done(cdev, -ETIME); break; case -EACCES: /* channel is not operational. */ cdev->private->imask >>= 1; cdev->private->iretry = 5; __ccw_device_disband_start(cdev); break; }}voidccw_device_disband_start(struct ccw_device *cdev){ /* After 60s disbanding is considered to have failed. */ ccw_device_set_timeout(cdev, 60*HZ); cdev->private->flags.pgid_single = 0; cdev->private->iretry = 5; cdev->private->imask = 0x80; __ccw_device_disband_start(cdev);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?