Commit 60033520 authored by Jens Axboe's avatar Jens Axboe

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
...@@ -172,8 +172,8 @@ EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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,10 +281,8 @@ void ide_retry_pc(ide_drive_t *drive) ...@@ -270,10 +281,8 @@ 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);
......
...@@ -258,11 +258,22 @@ static int ide_cd_breathe(ide_drive_t *drive, struct request *rq) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -427,9 +427,8 @@ static void ide_disk_unlock_native_capacity(ide_drive_t *drive) ...@@ -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) ...@@ -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;
} }
} }
......
...@@ -67,7 +67,15 @@ int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,21 +506,16 @@ void do_ide_request(struct request_queue *q) ...@@ -503,21 +506,16 @@ 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)
rq = blk_fetch_request(drive->queue);
spin_unlock_irq(q->queue_lock);
spin_lock_irq(&hwif->lock);
if (!rq) { if (!rq) {
ide_unlock_port(hwif); rq = bd->rq;
goto out; if (!rq) {
ide_unlock_port(hwif);
goto out;
}
} }
/* /*
...@@ -551,23 +549,24 @@ void do_ide_request(struct request_queue *q) ...@@ -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;
goto repeat; if (rq)
goto repeat;
ide_unlock_port(hwif);
goto out;
} }
} else } else {
goto plug_device; plug_device:
spin_unlock_irq(&hwif->lock);
ide_unlock_host(host);
ide_requeue_and_plug(drive, rq);
return BLK_STS_OK;
}
out: out:
spin_unlock_irq(&hwif->lock); spin_unlock_irq(&hwif->lock);
if (rq == NULL) if (rq == NULL)
ide_unlock_host(host); ide_unlock_host(host);
spin_lock_irq(q->queue_lock); return BLK_STS_OK;
return;
plug_device:
spin_unlock_irq(&hwif->lock);
ide_unlock_host(host);
plug_device_2:
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) ...@@ -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);
...@@ -27,7 +27,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) ...@@ -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) ...@@ -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;
......
...@@ -40,32 +40,20 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) ...@@ -40,32 +40,20 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
return ret; return ret;
} }
static void ide_end_sync_rq(struct request *rq, blk_status_t error)
{
complete(rq->end_io_data);
}
static int ide_pm_execute_rq(struct request *rq) static int ide_pm_execute_rq(struct request *rq)
{ {
struct request_queue *q = rq->q; struct request_queue *q = rq->q;
DECLARE_COMPLETION_ONSTACK(wait);
rq->end_io_data = &wait;
rq->end_io = ide_end_sync_rq;
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
if (unlikely(blk_queue_dying(q))) { if (unlikely(blk_queue_dying(q))) {
rq->rq_flags |= RQF_QUIET; rq->rq_flags |= RQF_QUIET;
scsi_req(rq)->result = -ENXIO; scsi_req(rq)->result = -ENXIO;
__blk_end_request_all(rq, BLK_STS_OK);
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
blk_mq_end_request(rq, BLK_STS_OK);
return -ENXIO; return -ENXIO;
} }
__elv_add_request(q, rq, ELEVATOR_INSERT_FRONT);
__blk_run_queue_uncond(q);
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
blk_execute_rq(q, NULL, rq, true);
wait_for_completion_io(&wait);
return scsi_req(rq)->result ? -EIO : 0; return scsi_req(rq)->result ? -EIO : 0;
} }
...@@ -79,6 +67,8 @@ int generic_ide_resume(struct device *dev) ...@@ -79,6 +67,8 @@ int generic_ide_resume(struct device *dev)
struct ide_pm_state rqpm; struct ide_pm_state rqpm;
int err; int err;
blk_mq_start_stopped_hw_queues(drive->queue, true);
if (ide_port_acpi(hwif)) { if (ide_port_acpi(hwif)) {
/* call ACPI _PS0 / _STM only once */ /* call ACPI _PS0 / _STM only once */
if ((drive->dn & 1) == 0 || pair == NULL) { if ((drive->dn & 1) == 0 || pair == NULL) {
...@@ -226,15 +216,14 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) ...@@ -226,15 +216,14 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
#endif #endif
spin_lock_irqsave(q->queue_lock, flags); spin_lock_irqsave(q->queue_lock, flags);
if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND)
blk_stop_queue(q); blk_mq_stop_hw_queues(q);
else else
drive->dev_flags &= ~IDE_DFLAG_BLOCKED; drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
spin_unlock_irqrestore(q->queue_lock, flags); spin_unlock_irqrestore(q->queue_lock, flags);
drive->hwif->rq = NULL; drive->hwif->rq = NULL;
if (blk_end_request(rq, BLK_STS_OK, 0)) blk_mq_end_request(rq, BLK_STS_OK);
BUG();
} }
void ide_check_pm_state(ide_drive_t *drive, struct request *rq) void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
...@@ -260,7 +249,6 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq) ...@@ -260,7 +249,6 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
ide_hwif_t *hwif = drive->hwif; ide_hwif_t *hwif = drive->hwif;
const struct ide_tp_ops *tp_ops = hwif->tp_ops; const struct ide_tp_ops *tp_ops = hwif->tp_ops;
struct request_queue *q = drive->queue; struct request_queue *q = drive->queue;
unsigned long flags;
int rc; int rc;
#ifdef DEBUG_PM #ifdef DEBUG_PM
printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
...@@ -274,8 +262,6 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq) ...@@ -274,8 +262,6 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
if (rc) if (rc)
printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
spin_lock_irqsave(q->queue_lock, flags); blk_mq_start_hw_queues(q);
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
} }
} }
...@@ -750,6 +750,11 @@ static void ide_initialize_rq(struct request *rq) ...@@ -750,6 +750,11 @@ static void ide_initialize_rq(struct request *rq)
req->sreq.sense = req->sense; req->sreq.sense = req->sense;
} }
static const struct blk_mq_ops ide_mq_ops = {
.queue_rq = ide_queue_rq,
.initialize_rq_fn = ide_initialize_rq,
};
/* /*
* init request queue * init request queue
*/ */
...@@ -759,6 +764,7 @@ static int ide_init_queue(ide_drive_t *drive) ...@@ -759,6 +764,7 @@ static int ide_init_queue(ide_drive_t *drive)
ide_hwif_t *hwif = drive->hwif; ide_hwif_t *hwif = drive->hwif;
int max_sectors = 256; int max_sectors = 256;
int max_sg_entries = PRD_ENTRIES; int max_sg_entries = PRD_ENTRIES;
struct blk_mq_tag_set *set;
/* /*
* Our default set up assumes the normal IDE case, * Our default set up assumes the normal IDE case,
...@@ -767,19 +773,26 @@ static int ide_init_queue(ide_drive_t *drive) ...@@ -767,19 +773,26 @@ static int ide_init_queue(ide_drive_t *drive)
* limits and LBA48 we could raise it but as yet * limits and LBA48 we could raise it but as yet
* do not. * do not.
*/ */
q = blk_alloc_queue_node(GFP_KERNEL, hwif_to_node(hwif), NULL);
if (!q) set = &drive->tag_set;
set->ops = &ide_mq_ops;
set->nr_hw_queues = 1;
set->queue_depth = 32;
set->reserved_tags = 1;
set->cmd_size = sizeof(struct ide_request);
set->numa_node = hwif_to_node(hwif);
set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
if (blk_mq_alloc_tag_set(set))
return 1; return 1;
q->request_fn = do_ide_request; q = blk_mq_init_queue(set);
q->initialize_rq_fn = ide_initialize_rq; if (IS_ERR(q)) {
q->cmd_size = sizeof(struct ide_request); blk_mq_free_tag_set(set);
blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
if (blk_init_allocated_queue(q) < 0) {
blk_cleanup_queue(q);
return 1; return 1;
} }
blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
q->queuedata = drive; q->queuedata = drive;
blk_queue_segment_boundary(q, 0xffff); blk_queue_segment_boundary(q, 0xffff);
...@@ -965,8 +978,12 @@ static void drive_release_dev (struct device *dev) ...@@ -965,8 +978,12 @@ static void drive_release_dev (struct device *dev)
ide_proc_unregister_device(drive); ide_proc_unregister_device(drive);
if (drive->sense_rq)
blk_mq_free_request(drive->sense_rq);
blk_cleanup_queue(drive->queue); blk_cleanup_queue(drive->queue);
drive->queue = NULL; drive->queue = NULL;
blk_mq_free_tag_set(&drive->tag_set);
drive->dev_flags &= ~IDE_DFLAG_PRESENT; drive->dev_flags &= ~IDE_DFLAG_PRESENT;
...@@ -1133,6 +1150,28 @@ static void ide_port_cable_detect(ide_hwif_t *hwif) ...@@ -1133,6 +1150,28 @@ static void ide_port_cable_detect(ide_hwif_t *hwif)
} }
} }
/*
* Deferred request list insertion handler
*/
static void drive_rq_insert_work(struct work_struct *work)
{
ide_drive_t *drive = container_of(work, ide_drive_t, rq_work);
ide_hwif_t *hwif = drive->hwif;
struct request *rq;
LIST_HEAD(list);
spin_lock_irq(&hwif->lock);
if (!list_empty(&drive->rq_list))
list_splice_init(&drive->rq_list, &list);
spin_unlock_irq(&hwif->lock);
while (!list_empty(&list)) {
rq = list_first_entry(&list, struct request, queuelist);
list_del_init(&rq->queuelist);
blk_execute_rq_nowait(drive->queue, rq->rq_disk, rq, true, NULL);
}
}
static const u8 ide_hwif_to_major[] = static const u8 ide_hwif_to_major[] =
{ IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
...@@ -1145,12 +1184,10 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif) ...@@ -1145,12 +1184,10 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif)
ide_port_for_each_dev(i, drive, hwif) { ide_port_for_each_dev(i, drive, hwif) {
u8 j = (hwif->index * MAX_DRIVES) + i; u8 j = (hwif->index * MAX_DRIVES) + i;
u16 *saved_id = drive->id; u16 *saved_id = drive->id;
struct request *saved_sense_rq = drive->sense_rq;
memset(drive, 0, sizeof(*drive)); memset(drive, 0, sizeof(*drive));
memset(saved_id, 0, SECTOR_SIZE); memset(saved_id, 0, SECTOR_SIZE);
drive->id = saved_id; drive->id = saved_id;
drive->sense_rq = saved_sense_rq;
drive->media = ide_disk; drive->media = ide_disk;
drive->select = (i << 4) | ATA_DEVICE_OBS; drive->select = (i << 4) | ATA_DEVICE_OBS;
...@@ -1166,6 +1203,9 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif) ...@@ -1166,6 +1203,9 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif)
INIT_LIST_HEAD(&drive->list); INIT_LIST_HEAD(&drive->list);
init_completion(&drive->gendev_rel_comp); init_completion(&drive->gendev_rel_comp);
INIT_WORK(&drive->rq_work, drive_rq_insert_work);
INIT_LIST_HEAD(&drive->rq_list);
} }
} }
...@@ -1255,7 +1295,6 @@ static void ide_port_free_devices(ide_hwif_t *hwif) ...@@ -1255,7 +1295,6 @@ static void ide_port_free_devices(ide_hwif_t *hwif)
int i; int i;
ide_port_for_each_dev(i, drive, hwif) { ide_port_for_each_dev(i, drive, hwif) {
kfree(drive->sense_rq);
kfree(drive->id); kfree(drive->id);
kfree(drive); kfree(drive);
} }
...@@ -1283,17 +1322,10 @@ static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) ...@@ -1283,17 +1322,10 @@ static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
if (drive->id == NULL) if (drive->id == NULL)
goto out_free_drive; goto out_free_drive;
drive->sense_rq = kmalloc(sizeof(struct request) +
sizeof(struct ide_request), GFP_KERNEL);
if (!drive->sense_rq)
goto out_free_id;
hwif->devices[i] = drive; hwif->devices[i] = drive;
} }
return 0; return 0;
out_free_id:
kfree(drive->id);
out_free_drive: out_free_drive:
kfree(drive); kfree(drive);
out_nomem: out_nomem:
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/ata.h> #include <linux/ata.h>
#include <linux/blkdev.h> #include <linux/blk-mq.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -529,6 +529,10 @@ struct ide_drive_s { ...@@ -529,6 +529,10 @@ struct ide_drive_s {
struct request_queue *queue; /* request queue */ struct request_queue *queue; /* request queue */
int (*prep_rq)(struct ide_drive_s *, struct request *);
struct blk_mq_tag_set tag_set;
struct request *rq; /* current request */ struct request *rq; /* current request */
void *driver_data; /* extra driver data */ void *driver_data; /* extra driver data */
u16 *id; /* identification info */ u16 *id; /* identification info */
...@@ -612,6 +616,10 @@ struct ide_drive_s { ...@@ -612,6 +616,10 @@ struct ide_drive_s {
bool sense_rq_armed; bool sense_rq_armed;
struct request *sense_rq; struct request *sense_rq;
struct request_sense sense_data; struct request_sense sense_data;
/* async sense insertion */
struct work_struct rq_work;
struct list_head rq_list;
}; };
typedef struct ide_drive_s ide_drive_t; typedef struct ide_drive_s ide_drive_t;
...@@ -1089,6 +1097,7 @@ extern int ide_pci_clk; ...@@ -1089,6 +1097,7 @@ extern int ide_pci_clk;
int ide_end_rq(ide_drive_t *, struct request *, blk_status_t, unsigned int); int ide_end_rq(ide_drive_t *, struct request *, blk_status_t, unsigned int);
void ide_kill_rq(ide_drive_t *, struct request *); void ide_kill_rq(ide_drive_t *, struct request *);
void ide_insert_request_head(ide_drive_t *, struct request *);
void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int); void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int);
void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int); void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int);
...@@ -1208,7 +1217,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout); ...@@ -1208,7 +1217,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
extern void ide_timer_expiry(struct timer_list *t); extern void ide_timer_expiry(struct timer_list *t);
extern irqreturn_t ide_intr(int irq, void *dev_id); extern irqreturn_t ide_intr(int irq, void *dev_id);
extern void do_ide_request(struct request_queue *); extern blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);
extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq); extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq);
void ide_init_disk(struct gendisk *, ide_drive_t *); void ide_init_disk(struct gendisk *, ide_drive_t *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment