Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60033520 authored by Jens Axboe's avatar Jens Axboe
Browse files

ide: convert to blk-mq



ide-disk and ide-cd tested as working just fine, ide-tape and
ide-floppy haven't. But the latter don't require changes, so they
should work without issue.

Add helper function to insert a request from a work queue, since we
cannot invoke the blk-mq request insertion from IRQ context.

Cc: David Miller <davem@davemloft.net>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Tested-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarOmar Sandoval <osandov@fb.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent d0be1227
Loading
Loading
Loading
Loading
+17 −8
Original line number Original line Diff line number Diff line
@@ -172,8 +172,8 @@ EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
void ide_prep_sense(ide_drive_t *drive, struct request *rq)
void ide_prep_sense(ide_drive_t *drive, struct request *rq)
{
{
	struct request_sense *sense = &drive->sense_data;
	struct request_sense *sense = &drive->sense_data;
	struct request *sense_rq = drive->sense_rq;
	struct request *sense_rq;
	struct scsi_request *req = scsi_req(sense_rq);
	struct scsi_request *req;
	unsigned int cmd_len, sense_len;
	unsigned int cmd_len, sense_len;
	int err;
	int err;


@@ -196,9 +196,16 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq)
	if (ata_sense_request(rq) || drive->sense_rq_armed)
	if (ata_sense_request(rq) || drive->sense_rq_armed)
		return;
		return;


	sense_rq = drive->sense_rq;
	if (!sense_rq) {
		sense_rq = blk_mq_alloc_request(drive->queue, REQ_OP_DRV_IN,
					BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
		drive->sense_rq = sense_rq;
	}
	req = scsi_req(sense_rq);

	memset(sense, 0, sizeof(*sense));
	memset(sense, 0, sizeof(*sense));


	blk_rq_init(rq->q, sense_rq);
	scsi_req_init(req);
	scsi_req_init(req);


	err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
	err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
@@ -207,6 +214,8 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq)
		if (printk_ratelimit())
		if (printk_ratelimit())
			printk(KERN_WARNING PFX "%s: failed to map sense "
			printk(KERN_WARNING PFX "%s: failed to map sense "
					    "buffer\n", drive->name);
					    "buffer\n", drive->name);
		blk_mq_free_request(sense_rq);
		drive->sense_rq = NULL;
		return;
		return;
	}
	}


@@ -226,6 +235,8 @@ EXPORT_SYMBOL_GPL(ide_prep_sense);


int ide_queue_sense_rq(ide_drive_t *drive, void *special)
int ide_queue_sense_rq(ide_drive_t *drive, void *special)
{
{
	struct request *sense_rq = drive->sense_rq;

	/* deferred failure from ide_prep_sense() */
	/* deferred failure from ide_prep_sense() */
	if (!drive->sense_rq_armed) {
	if (!drive->sense_rq_armed) {
		printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
		printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
@@ -233,12 +244,12 @@ int ide_queue_sense_rq(ide_drive_t *drive, void *special)
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	drive->sense_rq->special = special;
	sense_rq->special = special;
	drive->sense_rq_armed = false;
	drive->sense_rq_armed = false;


	drive->hwif->rq = NULL;
	drive->hwif->rq = NULL;


	elv_add_request(drive->queue, drive->sense_rq, ELEVATOR_INSERT_FRONT);
	ide_insert_request_head(drive, sense_rq);
	return 0;
	return 0;
}
}
EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
@@ -270,11 +281,9 @@ void ide_retry_pc(ide_drive_t *drive)
	 */
	 */
	drive->hwif->rq = NULL;
	drive->hwif->rq = NULL;
	ide_requeue_and_plug(drive, failed_rq);
	ide_requeue_and_plug(drive, failed_rq);
	if (ide_queue_sense_rq(drive, pc)) {
	if (ide_queue_sense_rq(drive, pc))
		blk_start_request(failed_rq);
		ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(failed_rq));
		ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(failed_rq));
}
}
}
EXPORT_SYMBOL_GPL(ide_retry_pc);
EXPORT_SYMBOL_GPL(ide_retry_pc);


int ide_cd_expiry(ide_drive_t *drive)
int ide_cd_expiry(ide_drive_t *drive)
+94 −81
Original line number Original line Diff line number Diff line
@@ -258,11 +258,22 @@ static int ide_cd_breathe(ide_drive_t *drive, struct request *rq)
		/*
		/*
		 * take a breather
		 * take a breather
		 */
		 */
		blk_delay_queue(drive->queue, 1);
		blk_mq_requeue_request(rq, false);
		blk_mq_delay_kick_requeue_list(drive->queue, 1);
		return 1;
		return 1;
	}
	}
}
}


static void ide_cd_free_sense(ide_drive_t *drive)
{
	if (!drive->sense_rq)
		return;

	blk_mq_free_request(drive->sense_rq);
	drive->sense_rq = NULL;
	drive->sense_rq_armed = false;
}

/**
/**
 * Returns:
 * Returns:
 * 0: if the request should be continued.
 * 0: if the request should be continued.
@@ -516,6 +527,82 @@ static bool ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
	return false;
	return false;
}
}


/* standard prep_rq_fn that builds 10 byte cmds */
static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
{
	int hard_sect = queue_logical_block_size(q);
	long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
	unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
	struct scsi_request *req = scsi_req(rq);

	if (rq_data_dir(rq) == READ)
		req->cmd[0] = GPCMD_READ_10;
	else
		req->cmd[0] = GPCMD_WRITE_10;

	/*
	 * fill in lba
	 */
	req->cmd[2] = (block >> 24) & 0xff;
	req->cmd[3] = (block >> 16) & 0xff;
	req->cmd[4] = (block >>  8) & 0xff;
	req->cmd[5] = block & 0xff;

	/*
	 * and transfer length
	 */
	req->cmd[7] = (blocks >> 8) & 0xff;
	req->cmd[8] = blocks & 0xff;
	req->cmd_len = 10;
	return BLKPREP_OK;
}

/*
 * Most of the SCSI commands are supported directly by ATAPI devices.
 * This transform handles the few exceptions.
 */
static int ide_cdrom_prep_pc(struct request *rq)
{
	u8 *c = scsi_req(rq)->cmd;

	/* transform 6-byte read/write commands to the 10-byte version */
	if (c[0] == READ_6 || c[0] == WRITE_6) {
		c[8] = c[4];
		c[5] = c[3];
		c[4] = c[2];
		c[3] = c[1] & 0x1f;
		c[2] = 0;
		c[1] &= 0xe0;
		c[0] += (READ_10 - READ_6);
		scsi_req(rq)->cmd_len = 10;
		return BLKPREP_OK;
	}

	/*
	 * it's silly to pretend we understand 6-byte sense commands, just
	 * reject with ILLEGAL_REQUEST and the caller should take the
	 * appropriate action
	 */
	if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
		scsi_req(rq)->result = ILLEGAL_REQUEST;
		return BLKPREP_KILL;
	}

	return BLKPREP_OK;
}

static int ide_cdrom_prep_fn(ide_drive_t *drive, struct request *rq)
{
	if (!blk_rq_is_passthrough(rq)) {
		scsi_req_init(scsi_req(rq));

		return ide_cdrom_prep_fs(drive->queue, rq);
	} else if (blk_rq_is_scsi(rq))
		return ide_cdrom_prep_pc(rq);

	return 0;
}

static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
{
{
	ide_hwif_t *hwif = drive->hwif;
	ide_hwif_t *hwif = drive->hwif;
@@ -675,7 +762,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
out_end:
out_end:
	if (blk_rq_is_scsi(rq) && rc == 0) {
	if (blk_rq_is_scsi(rq) && rc == 0) {
		scsi_req(rq)->resid_len = 0;
		scsi_req(rq)->resid_len = 0;
		blk_end_request_all(rq, BLK_STS_OK);
		blk_mq_end_request(rq, BLK_STS_OK);
		hwif->rq = NULL;
		hwif->rq = NULL;
	} else {
	} else {
		if (sense && uptodate)
		if (sense && uptodate)
@@ -705,6 +792,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
		if (sense && rc == 2)
		if (sense && rc == 2)
			ide_error(drive, "request sense failure", stat);
			ide_error(drive, "request sense failure", stat);
	}
	}

	ide_cd_free_sense(drive);
	return ide_stopped;
	return ide_stopped;
}
}


@@ -729,7 +818,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
		 * We may be retrying this request after an error.  Fix up any
		 * We may be retrying this request after an error.  Fix up any
		 * weirdness which might be present in the request packet.
		 * weirdness which might be present in the request packet.
		 */
		 */
		q->prep_rq_fn(q, rq);
		ide_cdrom_prep_fn(drive, rq);
	}
	}


	/* fs requests *must* be hardware frame aligned */
	/* fs requests *must* be hardware frame aligned */
@@ -1323,82 +1412,6 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
	return nslots;
	return nslots;
}
}


/* standard prep_rq_fn that builds 10 byte cmds */
static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
{
	int hard_sect = queue_logical_block_size(q);
	long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
	unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
	struct scsi_request *req = scsi_req(rq);

	q->initialize_rq_fn(rq);

	if (rq_data_dir(rq) == READ)
		req->cmd[0] = GPCMD_READ_10;
	else
		req->cmd[0] = GPCMD_WRITE_10;

	/*
	 * fill in lba
	 */
	req->cmd[2] = (block >> 24) & 0xff;
	req->cmd[3] = (block >> 16) & 0xff;
	req->cmd[4] = (block >>  8) & 0xff;
	req->cmd[5] = block & 0xff;

	/*
	 * and transfer length
	 */
	req->cmd[7] = (blocks >> 8) & 0xff;
	req->cmd[8] = blocks & 0xff;
	req->cmd_len = 10;
	return BLKPREP_OK;
}

/*
 * Most of the SCSI commands are supported directly by ATAPI devices.
 * This transform handles the few exceptions.
 */
static int ide_cdrom_prep_pc(struct request *rq)
{
	u8 *c = scsi_req(rq)->cmd;

	/* transform 6-byte read/write commands to the 10-byte version */
	if (c[0] == READ_6 || c[0] == WRITE_6) {
		c[8] = c[4];
		c[5] = c[3];
		c[4] = c[2];
		c[3] = c[1] & 0x1f;
		c[2] = 0;
		c[1] &= 0xe0;
		c[0] += (READ_10 - READ_6);
		scsi_req(rq)->cmd_len = 10;
		return BLKPREP_OK;
	}

	/*
	 * it's silly to pretend we understand 6-byte sense commands, just
	 * reject with ILLEGAL_REQUEST and the caller should take the
	 * appropriate action
	 */
	if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
		scsi_req(rq)->result = ILLEGAL_REQUEST;
		return BLKPREP_KILL;
	}

	return BLKPREP_OK;
}

static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
{
	if (!blk_rq_is_passthrough(rq))
		return ide_cdrom_prep_fs(q, rq);
	else if (blk_rq_is_scsi(rq))
		return ide_cdrom_prep_pc(rq);

	return 0;
}

struct cd_list_entry {
struct cd_list_entry {
	const char	*id_model;
	const char	*id_model;
	const char	*id_firmware;
	const char	*id_firmware;
@@ -1508,7 +1521,7 @@ static int ide_cdrom_setup(ide_drive_t *drive)


	ide_debug_log(IDE_DBG_PROBE, "enter");
	ide_debug_log(IDE_DBG_PROBE, "enter");


	blk_queue_prep_rq(q, ide_cdrom_prep_fn);
	drive->prep_rq = ide_cdrom_prep_fn;
	blk_queue_dma_alignment(q, 31);
	blk_queue_dma_alignment(q, 31);
	blk_queue_update_dma_pad(q, 15);
	blk_queue_update_dma_pad(q, 15);


@@ -1569,7 +1582,7 @@ static void ide_cd_release(struct device *dev)
	if (devinfo->handle == drive)
	if (devinfo->handle == drive)
		unregister_cdrom(devinfo);
		unregister_cdrom(devinfo);
	drive->driver_data = NULL;
	drive->driver_data = NULL;
	blk_queue_prep_rq(drive->queue, NULL);
	drive->prep_rq = NULL;
	g->private_data = NULL;
	g->private_data = NULL;
	put_disk(g);
	put_disk(g);
	kfree(info);
	kfree(info);
+2 −3
Original line number Original line Diff line number Diff line
@@ -427,9 +427,8 @@ static void ide_disk_unlock_native_capacity(ide_drive_t *drive)
		drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */
		drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */
}
}


static int idedisk_prep_fn(struct request_queue *q, struct request *rq)
static int idedisk_prep_fn(ide_drive_t *drive, struct request *rq)
{
{
	ide_drive_t *drive = q->queuedata;
	struct ide_cmd *cmd;
	struct ide_cmd *cmd;


	if (req_op(rq) != REQ_OP_FLUSH)
	if (req_op(rq) != REQ_OP_FLUSH)
@@ -548,7 +547,7 @@ static void update_flush(ide_drive_t *drive)


		if (barrier) {
		if (barrier) {
			wc = true;
			wc = true;
			blk_queue_prep_rq(drive->queue, idedisk_prep_fn);
			drive->prep_rq = idedisk_prep_fn;
		}
		}
	}
	}


+56 −44
Original line number Original line Diff line number Diff line
@@ -67,7 +67,15 @@ int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error,
		ide_dma_on(drive);
		ide_dma_on(drive);
	}
	}


	return blk_end_request(rq, error, nr_bytes);
	if (!blk_update_request(rq, error, nr_bytes)) {
		if (rq == drive->sense_rq)
			drive->sense_rq = NULL;

		__blk_mq_end_request(rq, error);
		return 0;
	}

	return 1;
}
}
EXPORT_SYMBOL_GPL(ide_end_rq);
EXPORT_SYMBOL_GPL(ide_end_rq);


@@ -307,8 +315,6 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
{
{
	ide_startstop_t startstop;
	ide_startstop_t startstop;


	BUG_ON(!(rq->rq_flags & RQF_STARTED));

#ifdef DEBUG
#ifdef DEBUG
	printk("%s: start_request: current=0x%08lx\n",
	printk("%s: start_request: current=0x%08lx\n",
		drive->hwif->name, (unsigned long) rq);
		drive->hwif->name, (unsigned long) rq);
@@ -320,6 +326,9 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
		goto kill_rq;
		goto kill_rq;
	}
	}


	if (drive->prep_rq && drive->prep_rq(drive, rq))
		return ide_stopped;

	if (ata_pm_request(rq))
	if (ata_pm_request(rq))
		ide_check_pm_state(drive, rq);
		ide_check_pm_state(drive, rq);


@@ -430,44 +439,38 @@ static inline void ide_unlock_host(struct ide_host *host)
	}
	}
}
}


static void __ide_requeue_and_plug(struct request_queue *q, struct request *rq)
{
	if (rq)
		blk_requeue_request(q, rq);
	if (rq || blk_peek_request(q)) {
		/* Use 3ms as that was the old plug delay */
		blk_delay_queue(q, 3);
	}
}

void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
{
{
	struct request_queue *q = drive->queue;
	struct request_queue *q = drive->queue;
	unsigned long flags;


	spin_lock_irqsave(q->queue_lock, flags);
	/* Use 3ms as that was the old plug delay */
	__ide_requeue_and_plug(q, rq);
	if (rq) {
	spin_unlock_irqrestore(q->queue_lock, flags);
		blk_mq_requeue_request(rq, false);
		blk_mq_delay_kick_requeue_list(q, 3);
	} else
		blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3);
}
}


/*
/*
 * Issue a new request to a device.
 * Issue a new request to a device.
 */
 */
void do_ide_request(struct request_queue *q)
blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
			  const struct blk_mq_queue_data *bd)
{
{
	ide_drive_t	*drive = q->queuedata;
	ide_drive_t	*drive = hctx->queue->queuedata;
	ide_hwif_t	*hwif = drive->hwif;
	ide_hwif_t	*hwif = drive->hwif;
	struct ide_host *host = hwif->host;
	struct ide_host *host = hwif->host;
	struct request	*rq = NULL;
	struct request	*rq = NULL;
	ide_startstop_t	startstop;
	ide_startstop_t	startstop;


	spin_unlock_irq(q->queue_lock);

	/* HLD do_request() callback might sleep, make sure it's okay */
	/* HLD do_request() callback might sleep, make sure it's okay */
	might_sleep();
	might_sleep();


	if (ide_lock_host(host, hwif))
	if (ide_lock_host(host, hwif))
		goto plug_device_2;
		return BLK_STS_DEV_RESOURCE;

	rq = bd->rq;
	blk_mq_start_request(rq);


	spin_lock_irq(&hwif->lock);
	spin_lock_irq(&hwif->lock);


@@ -503,22 +506,17 @@ void do_ide_request(struct request_queue *q)
		hwif->cur_dev = drive;
		hwif->cur_dev = drive;
		drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
		drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);


		spin_unlock_irq(&hwif->lock);
		spin_lock_irq(q->queue_lock);
		/*
		/*
		 * we know that the queue isn't empty, but this can happen
		 * we know that the queue isn't empty, but this can happen
		 * if the q->prep_rq_fn() decides to kill a request
		 * if the q->prep_rq_fn() decides to kill a request
		 */
		 */
		if (!rq)
		if (!rq) {
			rq = blk_fetch_request(drive->queue);
			rq = bd->rq;

		spin_unlock_irq(q->queue_lock);
		spin_lock_irq(&hwif->lock);

			if (!rq) {
			if (!rq) {
				ide_unlock_port(hwif);
				ide_unlock_port(hwif);
				goto out;
				goto out;
			}
			}
		}


		/*
		/*
		 * Sanity: don't accept a request that isn't a PM request
		 * Sanity: don't accept a request that isn't a PM request
@@ -551,23 +549,24 @@ void do_ide_request(struct request_queue *q)
		if (startstop == ide_stopped) {
		if (startstop == ide_stopped) {
			rq = hwif->rq;
			rq = hwif->rq;
			hwif->rq = NULL;
			hwif->rq = NULL;
			if (rq)
				goto repeat;
				goto repeat;
			ide_unlock_port(hwif);
			goto out;
		}
		}
	} else
	} else {
		goto plug_device;
plug_device:
out:
		spin_unlock_irq(&hwif->lock);
		spin_unlock_irq(&hwif->lock);
	if (rq == NULL)
		ide_unlock_host(host);
		ide_unlock_host(host);
	spin_lock_irq(q->queue_lock);
		ide_requeue_and_plug(drive, rq);
	return;
		return BLK_STS_OK;
	}


plug_device:
out:
	spin_unlock_irq(&hwif->lock);
	spin_unlock_irq(&hwif->lock);
	if (rq == NULL)
		ide_unlock_host(host);
		ide_unlock_host(host);
plug_device_2:
	return BLK_STS_OK;
	spin_lock_irq(q->queue_lock);
	__ide_requeue_and_plug(q, rq);
}
}


static int drive_is_ready(ide_drive_t *drive)
static int drive_is_ready(ide_drive_t *drive)
@@ -887,3 +886,16 @@ void ide_pad_transfer(ide_drive_t *drive, int write, int len)
	}
	}
}
}
EXPORT_SYMBOL_GPL(ide_pad_transfer);
EXPORT_SYMBOL_GPL(ide_pad_transfer);

void ide_insert_request_head(ide_drive_t *drive, struct request *rq)
{
	ide_hwif_t *hwif = drive->hwif;
	unsigned long flags;

	spin_lock_irqsave(&hwif->lock, flags);
	list_add_tail(&rq->queuelist, &drive->rq_list);
	spin_unlock_irqrestore(&hwif->lock, flags);

	kblockd_schedule_work(&drive->rq_work);
}
EXPORT_SYMBOL_GPL(ide_insert_request_head);
+2 −2
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
		spin_unlock_irq(&hwif->lock);
		spin_unlock_irq(&hwif->lock);


		if (start_queue)
		if (start_queue)
			blk_run_queue(q);
			blk_mq_run_hw_queues(q, true);
		return;
		return;
	}
	}
	spin_unlock_irq(&hwif->lock);
	spin_unlock_irq(&hwif->lock);
@@ -54,7 +54,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
	scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
	scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
	scsi_req(rq)->cmd_len = 1;
	scsi_req(rq)->cmd_len = 1;
	ide_req(rq)->type = ATA_PRIV_MISC;
	ide_req(rq)->type = ATA_PRIV_MISC;
	elv_add_request(q, rq, ELEVATOR_INSERT_FRONT);
	ide_insert_request_head(drive, rq);


out:
out:
	return;
	return;
Loading