summaryrefslogtreecommitdiffstats
path: root/drivers/block/skd_main.c
diff options
context:
space:
mode:
authorBart Van Assche <bart.vanassche@wdc.com>2017-08-17 22:13:33 +0200
committerJens Axboe <axboe@kernel.dk>2017-08-18 16:45:29 +0200
commita74d5b76fab971081187f446683121a08e06944e (patch)
tree8c3090c494a26aa9b8166548bddf075f431d5bdb /drivers/block/skd_main.c
parentskd: Convert to blk-mq (diff)
downloadlinux-a74d5b76fab971081187f446683121a08e06944e.tar.xz
linux-a74d5b76fab971081187f446683121a08e06944e.zip
skd: Switch to block layer timeout mechanism
Remove the timeout slot variables and rely on the block layer to detect request timeouts. Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Hannes Reinecke <hare@suse.de> Cc: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/block/skd_main.c')
-rw-r--r--drivers/block/skd_main.c117
1 files changed, 31 insertions, 86 deletions
diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c
index 3590f9a775ae..a982de2014cc 100644
--- a/drivers/block/skd_main.c
+++ b/drivers/block/skd_main.c
@@ -105,9 +105,6 @@ MODULE_VERSION(DRV_VERSION "-" DRV_BUILD_ID);
#define SKD_ID_SLOT_MASK 0x00FFu
#define SKD_ID_SLOT_AND_TABLE_MASK 0x03FFu
-#define SKD_N_TIMEOUT_SLOT 4u
-#define SKD_TIMEOUT_SLOT_MASK 3u
-
#define SKD_N_MAX_SECTORS 2048u
#define SKD_MAX_RETRIES 2u
@@ -125,7 +122,6 @@ enum skd_drvr_state {
SKD_DRVR_STATE_ONLINE,
SKD_DRVR_STATE_PAUSING,
SKD_DRVR_STATE_PAUSED,
- SKD_DRVR_STATE_DRAINING_TIMEOUT,
SKD_DRVR_STATE_RESTARTING,
SKD_DRVR_STATE_RESUMING,
SKD_DRVR_STATE_STOPPING,
@@ -142,7 +138,6 @@ enum skd_drvr_state {
#define SKD_WAIT_BOOT_TIMO SKD_TIMER_SECONDS(90u)
#define SKD_STARTING_TIMO SKD_TIMER_SECONDS(8u)
#define SKD_RESTARTING_TIMO SKD_TIMER_MINUTES(4u)
-#define SKD_DRAINING_TIMO SKD_TIMER_SECONDS(6u)
#define SKD_BUSY_TIMO SKD_TIMER_MINUTES(20u)
#define SKD_STARTED_BUSY_TIMO SKD_TIMER_SECONDS(60u)
#define SKD_START_WAIT_SECONDS 90u
@@ -185,7 +180,6 @@ struct skd_request_context {
u8 flush_cmd;
- u32 timeout_stamp;
enum dma_data_direction data_dir;
struct scatterlist *sg;
u32 n_sg;
@@ -252,8 +246,6 @@ struct skd_device {
u32 num_fitmsg_context;
u32 num_req_context;
- atomic_t timeout_slot[SKD_N_TIMEOUT_SLOT];
- atomic_t timeout_stamp;
struct skd_fitmsg_context *skmsg_table;
struct skd_special_context internal_skspcl;
@@ -464,7 +456,6 @@ static bool skd_fail_all(struct request_queue *q)
case SKD_DRVR_STATE_BUSY:
case SKD_DRVR_STATE_BUSY_IMMINENT:
case SKD_DRVR_STATE_BUSY_ERASE:
- case SKD_DRVR_STATE_DRAINING_TIMEOUT:
return false;
case SKD_DRVR_STATE_BUSY_SANITIZE:
@@ -492,7 +483,6 @@ static void skd_process_request(struct request *req, bool last)
u32 count;
int data_dir;
__be64 be_dmaa;
- u32 timo_slot;
int flush, fua;
WARN_ONCE(tag >= skd_max_queue_depth, "%#x > %#x (nr_requests = %lu)\n",
@@ -577,13 +567,6 @@ static void skd_process_request(struct request *req, bool last)
skmsg->length += sizeof(struct skd_scsi_request);
fmh->num_protocol_cmds_coalesced++;
- /*
- * Update the active request counts.
- * Capture the timeout timestamp.
- */
- skreq->timeout_stamp = atomic_read(&skdev->timeout_stamp);
- timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK;
- atomic_inc(&skdev->timeout_slot[timo_slot]);
atomic_inc(&skdev->in_flight);
dev_dbg(&skdev->pdev->dev, "req=0x%x busy=%d\n", skreq->id,
atomic_read(&skdev->in_flight));
@@ -617,6 +600,16 @@ static blk_status_t skd_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
return BLK_STS_OK;
}
+static enum blk_eh_timer_return skd_timed_out(struct request *req)
+{
+ struct skd_device *skdev = req->q->queuedata;
+
+ dev_err(&skdev->pdev->dev, "request with tag %#x timed out\n",
+ blk_mq_unique_tag(req));
+
+ return BLK_EH_HANDLED;
+}
+
static void skd_end_request(struct skd_device *skdev, struct request *req,
blk_status_t error)
{
@@ -635,6 +628,18 @@ static void skd_end_request(struct skd_device *skdev, struct request *req,
blk_mq_end_request(req, error);
}
+/* Only called in case of a request timeout */
+static void skd_softirq_done(struct request *req)
+{
+ struct skd_device *skdev = req->q->queuedata;
+ struct skd_request_context *skreq = blk_mq_rq_to_pdu(req);
+ unsigned long flags;
+
+ spin_lock_irqsave(&skdev->lock, flags);
+ skd_end_request(skdev, blk_mq_rq_from_pdu(skreq), BLK_STS_TIMEOUT);
+ spin_unlock_irqrestore(&skdev->lock, flags);
+}
+
static bool skd_preop_sg_list(struct skd_device *skdev,
struct skd_request_context *skreq)
{
@@ -733,8 +738,6 @@ static void skd_start_queue(struct work_struct *work)
static void skd_timer_tick(ulong arg)
{
struct skd_device *skdev = (struct skd_device *)arg;
-
- u32 timo_slot;
unsigned long reqflags;
u32 state;
@@ -751,35 +754,9 @@ static void skd_timer_tick(ulong arg)
if (state != skdev->drive_state)
skd_isr_fwstate(skdev);
- if (skdev->state != SKD_DRVR_STATE_ONLINE) {
+ if (skdev->state != SKD_DRVR_STATE_ONLINE)
skd_timer_tick_not_online(skdev);
- goto timer_func_out;
- }
- timo_slot = atomic_inc_return(&skdev->timeout_stamp) &
- SKD_TIMEOUT_SLOT_MASK;
-
- /*
- * All requests that happened during the previous use of
- * this slot should be done by now. The previous use was
- * over 7 seconds ago.
- */
- if (atomic_read(&skdev->timeout_slot[timo_slot]) == 0)
- goto timer_func_out;
-
- /* Something is overdue */
- dev_dbg(&skdev->pdev->dev, "found %d timeouts, draining busy=%d\n",
- atomic_read(&skdev->timeout_slot[timo_slot]),
- atomic_read(&skdev->in_flight));
- dev_err(&skdev->pdev->dev, "Overdue IOs (%d), busy %d\n",
- atomic_read(&skdev->timeout_slot[timo_slot]),
- atomic_read(&skdev->in_flight));
-
- skdev->timer_countdown = SKD_DRAINING_TIMO;
- skdev->state = SKD_DRVR_STATE_DRAINING_TIMEOUT;
- skdev->timo_slot = timo_slot;
- blk_stop_queue(skdev->queue);
-timer_func_out:
mod_timer(&skdev->timer, (jiffies + HZ));
spin_unlock_irqrestore(&skdev->lock, reqflags);
@@ -848,27 +825,6 @@ static void skd_timer_tick_not_online(struct skd_device *skdev)
case SKD_DRVR_STATE_PAUSED:
break;
- case SKD_DRVR_STATE_DRAINING_TIMEOUT:
- dev_dbg(&skdev->pdev->dev,
- "draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n",
- skdev->timo_slot, skdev->timer_countdown,
- atomic_read(&skdev->in_flight),
- atomic_read(&skdev->timeout_slot[skdev->timo_slot]));
- /* if the slot has cleared we can let the I/O continue */
- if (atomic_read(&skdev->timeout_slot[skdev->timo_slot]) == 0) {
- dev_dbg(&skdev->pdev->dev,
- "Slot drained, starting queue.\n");
- skdev->state = SKD_DRVR_STATE_ONLINE;
- blk_start_queue(skdev->queue);
- return;
- }
- if (skdev->timer_countdown > 0) {
- skdev->timer_countdown--;
- return;
- }
- skd_restart_device(skdev);
- break;
-
case SKD_DRVR_STATE_RESTARTING:
if (skdev->timer_countdown > 0) {
skdev->timer_countdown--;
@@ -1495,8 +1451,6 @@ static void skd_resolve_req_exception(struct skd_device *skdev,
static void skd_release_skreq(struct skd_device *skdev,
struct skd_request_context *skreq)
{
- u32 timo_slot;
-
/*
* Decrease the number of active requests.
* Also decrements the count in the timeout slot.
@@ -1504,10 +1458,6 @@ static void skd_release_skreq(struct skd_device *skdev,
SKD_ASSERT(atomic_read(&skdev->in_flight) > 0);
atomic_dec(&skdev->in_flight);
- timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK;
- SKD_ASSERT(atomic_read(&skdev->timeout_slot[timo_slot]) > 0);
- atomic_dec(&skdev->timeout_slot[timo_slot]);
-
/*
* Reclaim the skd_request_context
*/
@@ -1620,7 +1570,6 @@ static int skd_isr_completion_posted(struct skd_device *skdev,
if (skreq->n_sg > 0)
skd_postop_sg_list(skdev, skreq);
- /* Mark the FIT msg and timeout slot as free. */
skd_release_skreq(skdev, skreq);
/*
@@ -1979,13 +1928,8 @@ static void skd_recover_request(struct request *req, void *data, bool reserved)
static void skd_recover_requests(struct skd_device *skdev)
{
- int i;
-
blk_mq_tagset_busy_iter(&skdev->tag_set, skd_recover_request, skdev);
- for (i = 0; i < SKD_N_TIMEOUT_SLOT; i++)
- atomic_set(&skdev->timeout_slot[i], 0);
-
atomic_set(&skdev->in_flight, 0);
}
@@ -2917,6 +2861,10 @@ static int skd_cons_disk(struct skd_device *skdev)
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q);
+ blk_queue_rq_timeout(q, 8 * HZ);
+ blk_queue_rq_timed_out(q, skd_timed_out);
+ blk_queue_softirq_done(q, skd_softirq_done);
+
spin_lock_irqsave(&skdev->lock, flags);
dev_dbg(&skdev->pdev->dev, "stopping queue\n");
blk_mq_stop_hw_queues(skdev->queue);
@@ -3561,8 +3509,6 @@ const char *skd_skdev_state_to_str(enum skd_drvr_state state)
return "PAUSING";
case SKD_DRVR_STATE_PAUSED:
return "PAUSED";
- case SKD_DRVR_STATE_DRAINING_TIMEOUT:
- return "DRAINING_TIMEOUT";
case SKD_DRVR_STATE_RESTARTING:
return "RESTARTING";
case SKD_DRVR_STATE_RESUMING:
@@ -3616,9 +3562,8 @@ static void skd_log_skdev(struct skd_device *skdev, const char *event)
dev_dbg(&skdev->pdev->dev, " busy=%d limit=%d dev=%d lowat=%d\n",
atomic_read(&skdev->in_flight), skdev->cur_max_queue_depth,
skdev->dev_max_queue_depth, skdev->queue_low_water_mark);
- dev_dbg(&skdev->pdev->dev, " timestamp=0x%x cycle=%d cycle_ix=%d\n",
- atomic_read(&skdev->timeout_stamp), skdev->skcomp_cycle,
- skdev->skcomp_ix);
+ dev_dbg(&skdev->pdev->dev, " cycle=%d cycle_ix=%d\n",
+ skdev->skcomp_cycle, skdev->skcomp_ix);
}
static void skd_log_skreq(struct skd_device *skdev,
@@ -3632,8 +3577,8 @@ static void skd_log_skreq(struct skd_device *skdev,
dev_dbg(&skdev->pdev->dev, " state=%s(%d) id=0x%04x fitmsg=0x%04x\n",
skd_skreq_state_to_str(skreq->state), skreq->state, skreq->id,
skreq->fitmsg_id);
- dev_dbg(&skdev->pdev->dev, " timo=0x%x sg_dir=%d n_sg=%d\n",
- skreq->timeout_stamp, skreq->data_dir, skreq->n_sg);
+ dev_dbg(&skdev->pdev->dev, " sg_dir=%d n_sg=%d\n",
+ skreq->data_dir, skreq->n_sg);
dev_dbg(&skdev->pdev->dev,
"req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", req, lba, lba,