void dasd_int_handler()

in block/dasd.c [1634:1837]


void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
		      struct irb *irb)
{
	struct dasd_ccw_req *cqr, *next, *fcqr;
	struct dasd_device *device;
	unsigned long now;
	int nrf_suppressed = 0;
	int fp_suppressed = 0;
	u8 *sense = NULL;
	int expires;

	cqr = (struct dasd_ccw_req *) intparm;
	if (IS_ERR(irb)) {
		switch (PTR_ERR(irb)) {
		case -EIO:
			if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) {
				device = cqr->startdev;
				cqr->status = DASD_CQR_CLEARED;
				dasd_device_clear_timer(device);
				wake_up(&dasd_flush_wq);
				dasd_schedule_device_bh(device);
				return;
			}
			break;
		case -ETIMEDOUT:
			DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
					"request timed out\n", __func__);
			break;
		default:
			DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
					"unknown error %ld\n", __func__,
					PTR_ERR(irb));
		}
		dasd_handle_killed_request(cdev, intparm);
		return;
	}

	now = get_tod_clock();
	/* check for conditions that should be handled immediately */
	if (!cqr ||
	    !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
	      scsw_cstat(&irb->scsw) == 0)) {
		if (cqr)
			memcpy(&cqr->irb, irb, sizeof(*irb));
		device = dasd_device_from_cdev_locked(cdev);
		if (IS_ERR(device))
			return;
		/* ignore unsolicited interrupts for DIAG discipline */
		if (device->discipline == dasd_diag_discipline_pointer) {
			dasd_put_device(device);
			return;
		}

		/*
		 * In some cases 'File Protected' or 'No Record Found' errors
		 * might be expected and debug log messages for the
		 * corresponding interrupts shouldn't be written then.
		 * Check if either of the according suppress bits is set.
		 */
		sense = dasd_get_sense(irb);
		if (sense) {
			fp_suppressed = (sense[1] & SNS1_FILE_PROTECTED) &&
				test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
			nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) &&
				test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);

			/*
			 * Extent pool probably out-of-space.
			 * Stop device and check exhaust level.
			 */
			if (dasd_ese_oos_cond(sense)) {
				dasd_generic_space_exhaust(device, cqr);
				device->discipline->ext_pool_exhaust(device, cqr);
				dasd_put_device(device);
				return;
			}
		}
		if (!(fp_suppressed || nrf_suppressed))
			device->discipline->dump_sense_dbf(device, irb, "int");

		if (device->features & DASD_FEATURE_ERPLOG)
			device->discipline->dump_sense(device, cqr, irb);
		device->discipline->check_for_device_change(device, cqr, irb);
		dasd_put_device(device);
	}

	/* check for for attention message */
	if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) {
		device = dasd_device_from_cdev_locked(cdev);
		if (!IS_ERR(device)) {
			device->discipline->check_attention(device,
							    irb->esw.esw1.lpum);
			dasd_put_device(device);
		}
	}

	if (!cqr)
		return;

	device = (struct dasd_device *) cqr->startdev;
	if (!device ||
	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
		DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s",
				"invalid device in request");
		return;
	}

	if (dasd_ese_needs_format(cqr->block, irb)) {
		if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
			device->discipline->ese_read(cqr, irb);
			cqr->status = DASD_CQR_SUCCESS;
			cqr->stopclk = now;
			dasd_device_clear_timer(device);
			dasd_schedule_device_bh(device);
			return;
		}
		fcqr = device->discipline->ese_format(device, cqr, irb);
		if (IS_ERR(fcqr)) {
			if (PTR_ERR(fcqr) == -EINVAL) {
				cqr->status = DASD_CQR_ERROR;
				return;
			}
			/*
			 * If we can't format now, let the request go
			 * one extra round. Maybe we can format later.
			 */
			cqr->status = DASD_CQR_QUEUED;
			dasd_schedule_device_bh(device);
			return;
		} else {
			fcqr->status = DASD_CQR_QUEUED;
			cqr->status = DASD_CQR_QUEUED;
			list_add(&fcqr->devlist, &device->ccw_queue);
			dasd_schedule_device_bh(device);
			return;
		}
	}

	/* Check for clear pending */
	if (cqr->status == DASD_CQR_CLEAR_PENDING &&
	    scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {
		cqr->status = DASD_CQR_CLEARED;
		dasd_device_clear_timer(device);
		wake_up(&dasd_flush_wq);
		dasd_schedule_device_bh(device);
		return;
	}

	/* check status - the request might have been killed by dyn detach */
	if (cqr->status != DASD_CQR_IN_IO) {
		DBF_DEV_EVENT(DBF_DEBUG, device, "invalid status: bus_id %s, "
			      "status %02x", dev_name(&cdev->dev), cqr->status);
		return;
	}

	next = NULL;
	expires = 0;
	if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
	    scsw_cstat(&irb->scsw) == 0) {
		/* request was completed successfully */
		cqr->status = DASD_CQR_SUCCESS;
		cqr->stopclk = now;
		/* Start first request on queue if possible -> fast_io. */
		if (cqr->devlist.next != &device->ccw_queue) {
			next = list_entry(cqr->devlist.next,
					  struct dasd_ccw_req, devlist);
		}
	} else {  /* error */
		/* check for HPF error
		 * call discipline function to requeue all requests
		 * and disable HPF accordingly
		 */
		if (cqr->cpmode && dasd_check_hpf_error(irb) &&
		    device->discipline->handle_hpf_error)
			device->discipline->handle_hpf_error(device, irb);
		/*
		 * If we don't want complex ERP for this request, then just
		 * reset this and retry it in the fastpath
		 */
		if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
		    cqr->retries > 0) {
			if (cqr->lpm == dasd_path_get_opm(device))
				DBF_DEV_EVENT(DBF_DEBUG, device,
					      "default ERP in fastpath "
					      "(%i retries left)",
					      cqr->retries);
			if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
				cqr->lpm = dasd_path_get_opm(device);
			cqr->status = DASD_CQR_QUEUED;
			next = cqr;
		} else
			cqr->status = DASD_CQR_ERROR;
	}
	if (next && (next->status == DASD_CQR_QUEUED) &&
	    (!device->stopped)) {
		if (device->discipline->start_IO(next) == 0)
			expires = next->expires;
	}
	if (expires != 0)
		dasd_device_set_timer(device, expires);
	else
		dasd_device_clear_timer(device);
	dasd_schedule_device_bh(device);
}