Commit 2c46344a authored by Asai Thambi SP's avatar Asai Thambi SP Committed by Greg Kroah-Hartman

mtip32xx: Cleanup queued requests after surprise removal

commit 008e56d2 upstream.

Fail all pending requests after surprise removal of a drive.
Signed-off-by: default avatarVignesh Gunasekaran <vgunasekaran@micron.com>
Signed-off-by: default avatarSelvan Mani <smani@micron.com>
Signed-off-by: default avatarAsai Thambi S P <asamymuthupa@micron.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d45d26e4
...@@ -173,7 +173,13 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd) ...@@ -173,7 +173,13 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
{ {
struct request *rq; struct request *rq;
if (mtip_check_surprise_removal(dd->pdev))
return NULL;
rq = blk_mq_alloc_request(dd->queue, 0, __GFP_RECLAIM, true); rq = blk_mq_alloc_request(dd->queue, 0, __GFP_RECLAIM, true);
if (IS_ERR(rq))
return NULL;
return blk_mq_rq_to_pdu(rq); return blk_mq_rq_to_pdu(rq);
} }
...@@ -575,6 +581,8 @@ static void mtip_completion(struct mtip_port *port, ...@@ -575,6 +581,8 @@ static void mtip_completion(struct mtip_port *port,
dev_warn(&port->dd->pdev->dev, dev_warn(&port->dd->pdev->dev,
"Internal command %d completed with TFE\n", tag); "Internal command %d completed with TFE\n", tag);
command->comp_func = NULL;
command->comp_data = NULL;
complete(waiting); complete(waiting);
} }
...@@ -1009,12 +1017,14 @@ static bool mtip_pause_ncq(struct mtip_port *port, ...@@ -1009,12 +1017,14 @@ static bool mtip_pause_ncq(struct mtip_port *port,
* *
* @port Pointer to port data structure * @port Pointer to port data structure
* @timeout Max duration to wait (ms) * @timeout Max duration to wait (ms)
* @atomic gfp_t flag to indicate blockable context or not
* *
* return value * return value
* 0 Success * 0 Success
* -EBUSY Commands still active * -EBUSY Commands still active
*/ */
static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout,
gfp_t atomic)
{ {
unsigned long to; unsigned long to;
unsigned int n; unsigned int n;
...@@ -1025,16 +1035,21 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) ...@@ -1025,16 +1035,21 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout)
to = jiffies + msecs_to_jiffies(timeout); to = jiffies + msecs_to_jiffies(timeout);
do { do {
if (test_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags) && if (test_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags) &&
test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags) &&
atomic == GFP_KERNEL) {
msleep(20); msleep(20);
continue; /* svc thd is actively issuing commands */ continue; /* svc thd is actively issuing commands */
} }
if (atomic == GFP_KERNEL)
msleep(100); msleep(100);
else {
cpu_relax();
udelay(100);
}
if (mtip_check_surprise_removal(port->dd->pdev)) if (mtip_check_surprise_removal(port->dd->pdev))
goto err_fault; goto err_fault;
if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag))
goto err_fault;
/* /*
* Ignore s_active bit 0 of array element 0. * Ignore s_active bit 0 of array element 0.
...@@ -1096,6 +1111,10 @@ static int mtip_exec_internal_command(struct mtip_port *port, ...@@ -1096,6 +1111,10 @@ static int mtip_exec_internal_command(struct mtip_port *port,
} }
int_cmd = mtip_get_int_command(dd); int_cmd = mtip_get_int_command(dd);
if (!int_cmd) {
dbg_printk(MTIP_DRV_NAME "Unable to allocate tag for PIO cmd\n");
return -EFAULT;
}
set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
...@@ -1108,7 +1127,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, ...@@ -1108,7 +1127,7 @@ static int mtip_exec_internal_command(struct mtip_port *port,
if (fis->command != ATA_CMD_STANDBYNOW1) { if (fis->command != ATA_CMD_STANDBYNOW1) {
/* wait for io to complete if non atomic */ /* wait for io to complete if non atomic */
if (mtip_quiesce_io(port, if (mtip_quiesce_io(port,
MTIP_QUIESCE_IO_TIMEOUT_MS) < 0) { MTIP_QUIESCE_IO_TIMEOUT_MS, atomic) < 0) {
dev_warn(&dd->pdev->dev, dev_warn(&dd->pdev->dev,
"Failed to quiesce IO\n"); "Failed to quiesce IO\n");
mtip_put_int_command(dd, int_cmd); mtip_put_int_command(dd, int_cmd);
...@@ -3354,10 +3373,6 @@ static int mtip_standby_drive(struct driver_data *dd) ...@@ -3354,10 +3373,6 @@ static int mtip_standby_drive(struct driver_data *dd)
*/ */
static int mtip_hw_exit(struct driver_data *dd) static int mtip_hw_exit(struct driver_data *dd)
{ {
/*
* Send standby immediate (E0h) to the drive so that it
* saves its state.
*/
if (!dd->sr) { if (!dd->sr) {
/* de-initialize the port. */ /* de-initialize the port. */
mtip_deinit_port(dd->port); mtip_deinit_port(dd->port);
...@@ -3974,7 +3989,7 @@ static int mtip_block_initialize(struct driver_data *dd) ...@@ -3974,7 +3989,7 @@ static int mtip_block_initialize(struct driver_data *dd)
if (rv) { if (rv) {
dev_err(&dd->pdev->dev, dev_err(&dd->pdev->dev,
"Unable to allocate request queue\n"); "Unable to allocate request queue\n");
goto block_queue_alloc_init_error; goto block_queue_alloc_tag_error;
} }
/* Allocate the request queue. */ /* Allocate the request queue. */
...@@ -4086,8 +4101,9 @@ static int mtip_block_initialize(struct driver_data *dd) ...@@ -4086,8 +4101,9 @@ static int mtip_block_initialize(struct driver_data *dd)
read_capacity_error: read_capacity_error:
init_hw_cmds_error: init_hw_cmds_error:
blk_cleanup_queue(dd->queue); blk_cleanup_queue(dd->queue);
blk_mq_free_tag_set(&dd->tags);
block_queue_alloc_init_error: block_queue_alloc_init_error:
blk_mq_free_tag_set(&dd->tags);
block_queue_alloc_tag_error:
mtip_hw_debugfs_exit(dd); mtip_hw_debugfs_exit(dd);
disk_index_error: disk_index_error:
spin_lock(&rssd_index_lock); spin_lock(&rssd_index_lock);
...@@ -4104,6 +4120,22 @@ static int mtip_block_initialize(struct driver_data *dd) ...@@ -4104,6 +4120,22 @@ static int mtip_block_initialize(struct driver_data *dd)
return rv; return rv;
} }
static void mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv)
{
struct driver_data *dd = (struct driver_data *)data;
struct mtip_cmd *cmd;
if (likely(!reserv))
blk_mq_complete_request(rq, -ENODEV);
else if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &dd->port->flags)) {
cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
if (cmd->comp_func)
cmd->comp_func(dd->port, MTIP_TAG_INTERNAL,
cmd, -ENODEV);
}
}
/* /*
* Block layer deinitialization function. * Block layer deinitialization function.
* *
...@@ -4135,12 +4167,23 @@ static int mtip_block_remove(struct driver_data *dd) ...@@ -4135,12 +4167,23 @@ static int mtip_block_remove(struct driver_data *dd)
} }
} }
if (!dd->sr) if (!dd->sr) {
/*
* Explicitly wait here for IOs to quiesce,
* as mtip_standby_drive usually won't wait for IOs.
*/
if (!mtip_quiesce_io(dd->port, MTIP_QUIESCE_IO_TIMEOUT_MS,
GFP_KERNEL))
mtip_standby_drive(dd); mtip_standby_drive(dd);
}
else else
dev_info(&dd->pdev->dev, "device %s surprise removal\n", dev_info(&dd->pdev->dev, "device %s surprise removal\n",
dd->disk->disk_name); dd->disk->disk_name);
blk_mq_freeze_queue_start(dd->queue);
blk_mq_stop_hw_queues(dd->queue);
blk_mq_all_tag_busy_iter(dd->tags.tags[0], mtip_no_dev_cleanup, dd);
/* /*
* Delete our gendisk structure. This also removes the device * Delete our gendisk structure. This also removes the device
* from /dev * from /dev
...@@ -4555,6 +4598,7 @@ static void mtip_pci_remove(struct pci_dev *pdev) ...@@ -4555,6 +4598,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
} while (atomic_read(&dd->irq_workers_active) != 0 && } while (atomic_read(&dd->irq_workers_active) != 0 &&
time_before(jiffies, to)); time_before(jiffies, to));
if (!dd->sr)
fsync_bdev(dd->bdev); fsync_bdev(dd->bdev);
if (atomic_read(&dd->irq_workers_active) != 0) { if (atomic_read(&dd->irq_workers_active) != 0) {
...@@ -4562,9 +4606,7 @@ static void mtip_pci_remove(struct pci_dev *pdev) ...@@ -4562,9 +4606,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
"Completion workers still active!\n"); "Completion workers still active!\n");
} }
if (dd->sr) blk_set_queue_dying(dd->queue);
blk_mq_stop_hw_queues(dd->queue);
set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag); set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
/* Clean up the block layer. */ /* Clean up the block layer. */
......
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