int dasd_start_IO()

in block/dasd.c [1386:1492]


int dasd_start_IO(struct dasd_ccw_req *cqr)
{
	struct dasd_device *device;
	int rc;
	char errorstring[ERRORLENGTH];

	/* Check the cqr */
	rc = dasd_check_cqr(cqr);
	if (rc) {
		cqr->intrc = rc;
		return rc;
	}
	device = (struct dasd_device *) cqr->startdev;
	if (((cqr->block &&
	      test_bit(DASD_FLAG_LOCK_STOLEN, &cqr->block->base->flags)) ||
	     test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) &&
	    !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
		DBF_DEV_EVENT(DBF_DEBUG, device, "start_IO: return request %p "
			      "because of stolen lock", cqr);
		cqr->status = DASD_CQR_ERROR;
		cqr->intrc = -EPERM;
		return -EPERM;
	}
	if (cqr->retries < 0) {
		/* internal error 14 - start_IO run out of retries */
		sprintf(errorstring, "14 %p", cqr);
		dev_err(&device->cdev->dev, "An error occurred in the DASD "
			"device driver, reason=%s\n", errorstring);
		cqr->status = DASD_CQR_ERROR;
		return -EIO;
	}
	cqr->startclk = get_tod_clock();
	cqr->starttime = jiffies;
	cqr->retries--;
	if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
		cqr->lpm &= dasd_path_get_opm(device);
		if (!cqr->lpm)
			cqr->lpm = dasd_path_get_opm(device);
	}
	if (cqr->cpmode == 1) {
		rc = ccw_device_tm_start(device->cdev, cqr->cpaddr,
					 (long) cqr, cqr->lpm);
	} else {
		rc = ccw_device_start(device->cdev, cqr->cpaddr,
				      (long) cqr, cqr->lpm, 0);
	}
	switch (rc) {
	case 0:
		cqr->status = DASD_CQR_IN_IO;
		break;
	case -EBUSY:
		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
			      "start_IO: device busy, retry later");
		break;
	case -EACCES:
		/* -EACCES indicates that the request used only a subset of the
		 * available paths and all these paths are gone. If the lpm of
		 * this request was only a subset of the opm (e.g. the ppm) then
		 * we just do a retry with all available paths.
		 * If we already use the full opm, something is amiss, and we
		 * need a full path verification.
		 */
		if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
			DBF_DEV_EVENT(DBF_WARNING, device,
				      "start_IO: selected paths gone (%x)",
				      cqr->lpm);
		} else if (cqr->lpm != dasd_path_get_opm(device)) {
			cqr->lpm = dasd_path_get_opm(device);
			DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
				      "start_IO: selected paths gone,"
				      " retry on all paths");
		} else {
			DBF_DEV_EVENT(DBF_WARNING, device, "%s",
				      "start_IO: all paths in opm gone,"
				      " do path verification");
			dasd_generic_last_path_gone(device);
			dasd_path_no_path(device);
			dasd_path_set_tbvpm(device,
					  ccw_device_get_path_mask(
						  device->cdev));
		}
		break;
	case -ENODEV:
		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
			      "start_IO: -ENODEV device gone, retry");
		break;
	case -EIO:
		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
			      "start_IO: -EIO device gone, retry");
		break;
	case -EINVAL:
		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
			      "start_IO: -EINVAL device currently "
			      "not accessible");
		break;
	default:
		/* internal error 11 - unknown rc */
		snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
		dev_err(&device->cdev->dev,
			"An error occurred in the DASD device driver, "
			"reason=%s\n", errorstring);
		BUG();
		break;
	}
	cqr->intrc = rc;
	return rc;
}