⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 device_fsm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (ret != 0)		/* Couldn't enable the subchannel for i/o. Sick device. */		return ret;	/* After 60s the device recognition is considered to have failed. */	ccw_device_set_timeout(cdev, 60*HZ);	/*	 * We used to start here with a sense pgid to find out whether a device	 * is locked by someone else. Unfortunately, the sense pgid command	 * code has other meanings on devices predating the path grouping	 * algorithm, so we start with sense id and box the device after an	 * timeout (or if sense pgid during path verification detects the device	 * is locked, as may happen on newer devices).	 */	cdev->private->flags.recog_done = 0;	cdev->private->state = DEV_STATE_SENSE_ID;	ccw_device_sense_id_start(cdev);	return 0;}/* * Handle timeout in device recognition. */static voidccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event){	int ret;	ret = ccw_device_cancel_halt_clear(cdev);	switch (ret) {	case 0:		ccw_device_recog_done(cdev, DEV_STATE_BOXED);		break;	case -ENODEV:		ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);		break;	default:		ccw_device_set_timeout(cdev, 3*HZ);	}}static voidccw_device_nopath_notify(void *data){	struct ccw_device *cdev;	struct subchannel *sch;	int ret;	cdev = (struct ccw_device *)data;	sch = to_subchannel(cdev->dev.parent);	/* Extra sanity. */	if (sch->lpm)		return;	ret = (sch->driver && sch->driver->notify) ?		sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0;	if (!ret) {		if (get_device(&sch->dev)) {			/* Driver doesn't want to keep device. */			cio_disable_subchannel(sch);			if (get_device(&cdev->dev)) {				PREPARE_WORK(&cdev->private->kick_work,					     ccw_device_call_sch_unregister,					     (void *)cdev);				queue_work(ccw_device_work,					   &cdev->private->kick_work);			} else				put_device(&sch->dev);		}	} else {		cio_disable_subchannel(sch);		ccw_device_set_timeout(cdev, 0);		cdev->private->flags.fake_irb = 0;		cdev->private->state = DEV_STATE_DISCONNECTED;		wake_up(&cdev->private->wait_q);	}}voidccw_device_verify_done(struct ccw_device *cdev, int err){	cdev->private->flags.doverify = 0;	switch (err) {	case -EOPNOTSUPP: /* path grouping not supported, just set online. */		cdev->private->options.pgroup = 0;	case 0:		ccw_device_done(cdev, DEV_STATE_ONLINE);		/* Deliver fake irb to device driver, if needed. */		if (cdev->private->flags.fake_irb) {			memset(&cdev->private->irb, 0, sizeof(struct irb));			cdev->private->irb.scsw = (struct scsw) {				.cc = 1,				.fctl = SCSW_FCTL_START_FUNC,				.actl = SCSW_ACTL_START_PEND,				.stctl = SCSW_STCTL_STATUS_PEND,			};			cdev->private->flags.fake_irb = 0;			if (cdev->handler)				cdev->handler(cdev, cdev->private->intparm,					      &cdev->private->irb);			memset(&cdev->private->irb, 0, sizeof(struct irb));		}		break;	case -ETIME:		ccw_device_done(cdev, DEV_STATE_BOXED);		break;	default:		PREPARE_WORK(&cdev->private->kick_work,			     ccw_device_nopath_notify, (void *)cdev);		queue_work(ccw_device_notify_work, &cdev->private->kick_work);		ccw_device_done(cdev, DEV_STATE_NOT_OPER);		break;	}}/* * Get device online. */intccw_device_online(struct ccw_device *cdev){	struct subchannel *sch;	int ret;	if ((cdev->private->state != DEV_STATE_OFFLINE) &&	    (cdev->private->state != DEV_STATE_BOXED))		return -EINVAL;	sch = to_subchannel(cdev->dev.parent);	if (css_init_done && !get_device(&cdev->dev))		return -ENODEV;	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);	if (ret != 0) {		/* Couldn't enable the subchannel for i/o. Sick device. */		if (ret == -ENODEV)			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);		return ret;	}	/* Do we want to do path grouping? */	if (!cdev->private->options.pgroup) {		/* No, set state online immediately. */		ccw_device_done(cdev, DEV_STATE_ONLINE);		return 0;	}	/* Do a SensePGID first. */	cdev->private->state = DEV_STATE_SENSE_PGID;	ccw_device_sense_pgid_start(cdev);	return 0;}voidccw_device_disband_done(struct ccw_device *cdev, int err){	switch (err) {	case 0:		ccw_device_done(cdev, DEV_STATE_OFFLINE);		break;	case -ETIME:		ccw_device_done(cdev, DEV_STATE_BOXED);		break;	default:		ccw_device_done(cdev, DEV_STATE_NOT_OPER);		break;	}}/* * Shutdown device. */intccw_device_offline(struct ccw_device *cdev){	struct subchannel *sch;	sch = to_subchannel(cdev->dev.parent);	if (stsch(sch->irq, &sch->schib) || !sch->schib.pmcw.dnv)		return -ENODEV;	if (cdev->private->state != DEV_STATE_ONLINE) {		if (sch->schib.scsw.actl != 0)			return -EBUSY;		return -EINVAL;	}	if (sch->schib.scsw.actl != 0)		return -EBUSY;	/* Are we doing path grouping? */	if (!cdev->private->options.pgroup) {		/* No, set state offline immediately. */		ccw_device_done(cdev, DEV_STATE_OFFLINE);		return 0;	}	/* Start Set Path Group commands. */	cdev->private->state = DEV_STATE_DISBAND_PGID;	ccw_device_disband_start(cdev);	return 0;}/* * Handle timeout in device online/offline process. */static voidccw_device_onoff_timeout(struct ccw_device *cdev, enum dev_event dev_event){	int ret;	ret = ccw_device_cancel_halt_clear(cdev);	switch (ret) {	case 0:		ccw_device_done(cdev, DEV_STATE_BOXED);		break;	case -ENODEV:		ccw_device_done(cdev, DEV_STATE_NOT_OPER);		break;	default:		ccw_device_set_timeout(cdev, 3*HZ);	}}/* * Handle not oper event in device recognition. */static voidccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event){	ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);}/* * Handle not operational event while offline. */static voidccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event){	struct subchannel *sch;	cdev->private->state = DEV_STATE_NOT_OPER;	sch = to_subchannel(cdev->dev.parent);	if (get_device(&cdev->dev)) {		PREPARE_WORK(&cdev->private->kick_work,			     ccw_device_call_sch_unregister, (void *)cdev);		queue_work(ccw_device_work, &cdev->private->kick_work);	}	wake_up(&cdev->private->wait_q);}/* * Handle not operational event while online. */static voidccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event){	struct subchannel *sch;	sch = to_subchannel(cdev->dev.parent);	if (sch->driver->notify &&	    sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) {			ccw_device_set_timeout(cdev, 0);			cdev->private->flags.fake_irb = 0;			cdev->private->state = DEV_STATE_DISCONNECTED;			wake_up(&cdev->private->wait_q);			return;	}	cdev->private->state = DEV_STATE_NOT_OPER;	cio_disable_subchannel(sch);	if (sch->schib.scsw.actl != 0) {		// FIXME: not-oper indication to device driver ?		ccw_device_call_handler(cdev);	}	if (get_device(&cdev->dev)) {		PREPARE_WORK(&cdev->private->kick_work,			     ccw_device_call_sch_unregister, (void *)cdev);		queue_work(ccw_device_work, &cdev->private->kick_work);	}	wake_up(&cdev->private->wait_q);}/* * Handle path verification event. */static voidccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event){	struct subchannel *sch;	if (!cdev->private->options.pgroup)		return;	if (cdev->private->state == DEV_STATE_W4SENSE) {		cdev->private->flags.doverify = 1;		return;	}	sch = to_subchannel(cdev->dev.parent);	/*	 * Since we might not just be coming from an interrupt from the	 * subchannel we have to update the schib.	 */	stsch(sch->irq, &sch->schib);	if (sch->schib.scsw.actl != 0 ||	    (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {		/*		 * No final status yet or final status not yet delivered		 * to the device driver. Can't do path verfication now,		 * delay until final status was delivered.		 */		cdev->private->flags.doverify = 1;		return;	}	/* Device is idle, we can do the path verification. */	cdev->private->state = DEV_STATE_VERIFY;	ccw_device_verify_start(cdev);}/* * Got an interrupt for a normal io (state online). */static voidccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event){	struct irb *irb;	irb = (struct irb *) __LC_IRB;	/* Check for unsolicited interrupt. */	if ((irb->scsw.stctl ==	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))	    && (!irb->scsw.cc)) {		if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&		    !irb->esw.esw0.erw.cons) {			/* Unit check but no sense data. Need basic sense. */			if (ccw_device_do_sense(cdev, irb) != 0)				goto call_handler_unsol;			memcpy(irb, &cdev->private->irb, sizeof(struct irb));			cdev->private->state = DEV_STATE_W4SENSE;			cdev->private->intparm = 0;			return;		}call_handler_unsol:		if (cdev->handler)			cdev->handler (cdev, 0, irb);		return;	}	/* Accumulate status and find out if a basic sense is needed. */	ccw_device_accumulate_irb(cdev, irb);	if (cdev->private->flags.dosense) {		if (ccw_device_do_sense(cdev, irb) == 0) {			cdev->private->state = DEV_STATE_W4SENSE;		}		return;	}	/* Call the handler. */	if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)		/* Start delayed path verification. */		ccw_device_online_verify(cdev, 0);}/* * Got an timeout in online state. */static voidccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event){	int ret;	ccw_device_set_timeout(cdev, 0);	ret = ccw_device_cancel_halt_clear(cdev);	if (ret == -EBUSY) {		ccw_device_set_timeout(cdev, 3*HZ);		cdev->private->state = DEV_STATE_TIMEOUT_KILL;		return;	}	if (ret == -ENODEV) {		struct subchannel *sch;		sch = to_subchannel(cdev->dev.parent);		if (!sch->lpm) {			PREPARE_WORK(&cdev->private->kick_work,				     ccw_device_nopath_notify, (void *)cdev);			queue_work(ccw_device_notify_work,				   &cdev->private->kick_work);		} else			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);	} else if (cdev->handler)		cdev->handler(cdev, cdev->private->intparm,			      ERR_PTR(-ETIMEDOUT));}/* * Got an interrupt for a basic sense. */voidccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event){	struct irb *irb;	irb = (struct irb *) __LC_IRB;	/* Check for unsolicited interrupt. */	if (irb->scsw.stctl ==	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {		if (irb->scsw.cc == 1)			/* Basic sense hasn't started. Try again. */			ccw_device_do_sense(cdev, irb);		else {			printk("Huh? %s(%s): unsolicited interrupt...\n",			       __FUNCTION__, cdev->dev.bus_id);			if (cdev->handler)				cdev->handler (cdev, 0, irb);		}		return;	}	/* Add basic sense info to irb. */	ccw_device_accumulate_basic_sense(cdev, irb);	if (cdev->private->flags.dosense) {		/* Another basic sense is needed. */		ccw_device_do_sense(cdev, irb);		return;	}	cdev->private->state = DEV_STATE_ONLINE;	/* Call the handler. */	if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)		/* Start delayed path verification. */		ccw_device_online_verify(cdev, 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -