static int dasd_eckd_format_process_data()

in block/dasd_eckd.c [2954:3076]


static int dasd_eckd_format_process_data(struct dasd_device *base,
					 struct format_data_t *fdata,
					 int enable_pav, int tpm,
					 struct eckd_count *fmt_buffer, int rpt,
					 struct irb *irb)
{
	struct dasd_eckd_private *private = base->private;
	struct dasd_ccw_req *cqr, *n;
	struct list_head format_queue;
	struct dasd_device *device;
	char *sense = NULL;
	int old_start, old_stop, format_step;
	int step, retry;
	int rc;

	rc = dasd_eckd_format_sanity_checks(base, fdata);
	if (rc)
		return rc;

	INIT_LIST_HEAD(&format_queue);

	old_start = fdata->start_unit;
	old_stop = fdata->stop_unit;

	if (!tpm && fmt_buffer != NULL) {
		/* Command Mode / Format Check */
		format_step = 1;
	} else if (tpm && fmt_buffer != NULL) {
		/* Transport Mode / Format Check */
		format_step = DASD_CQR_MAX_CCW / rpt;
	} else {
		/* Normal Formatting */
		format_step = DASD_CQR_MAX_CCW /
			recs_per_track(&private->rdc_data, 0, fdata->blksize);
	}

	do {
		retry = 0;
		while (fdata->start_unit <= old_stop) {
			step = fdata->stop_unit - fdata->start_unit + 1;
			if (step > format_step) {
				fdata->stop_unit =
					fdata->start_unit + format_step - 1;
			}

			cqr = dasd_eckd_format_build_ccw_req(base, fdata,
							     enable_pav, tpm,
							     fmt_buffer, rpt);
			if (IS_ERR(cqr)) {
				rc = PTR_ERR(cqr);
				if (rc == -ENOMEM) {
					if (list_empty(&format_queue))
						goto out;
					/*
					 * not enough memory available, start
					 * requests retry after first requests
					 * were finished
					 */
					retry = 1;
					break;
				}
				goto out_err;
			}
			list_add_tail(&cqr->blocklist, &format_queue);

			if (fmt_buffer) {
				step = fdata->stop_unit - fdata->start_unit + 1;
				fmt_buffer += rpt * step;
			}
			fdata->start_unit = fdata->stop_unit + 1;
			fdata->stop_unit = old_stop;
		}

		rc = dasd_sleep_on_queue(&format_queue);

out_err:
		list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
			device = cqr->startdev;
			private = device->private;

			if (cqr->status == DASD_CQR_FAILED) {
				/*
				 * Only get sense data if called by format
				 * check
				 */
				if (fmt_buffer && irb) {
					sense = dasd_get_sense(&cqr->irb);
					memcpy(irb, &cqr->irb, sizeof(*irb));
				}
				rc = -EIO;
			}
			list_del_init(&cqr->blocklist);
			dasd_ffree_request(cqr, device);
			private->count--;
		}

		if (rc && rc != -EIO)
			goto out;
		if (rc == -EIO) {
			/*
			 * In case fewer than the expected records are on the
			 * track, we will most likely get a 'No Record Found'
			 * error (in command mode) or a 'File Protected' error
			 * (in transport mode). Those particular cases shouldn't
			 * pass the -EIO to the IOCTL, therefore reset the rc
			 * and continue.
			 */
			if (sense &&
			    (sense[1] & SNS1_NO_REC_FOUND ||
			     sense[1] & SNS1_FILE_PROTECTED))
				retry = 1;
			else
				goto out;
		}

	} while (retry);

out:
	fdata->start_unit = old_start;
	fdata->stop_unit = old_stop;

	return rc;
}