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 + -
显示快捷键?