On 3 November 2017 at 14:20, Adrian Hunter <adrian.hunter@xxxxxxxxx> wrote: > card_busy_detect() doesn't set a correct timeout, and it doesn't take care > of error status bits. Stop using it for blk-mq. I think this changelog isn't very descriptive. Could you please work on that for the next version. > > Signed-off-by: Adrian Hunter <adrian.hunter@xxxxxxxxx> > --- > drivers/mmc/core/block.c | 117 +++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 109 insertions(+), 8 deletions(-) > > diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c > index 0c29b1d8d545..5c5ff3c34313 100644 > --- a/drivers/mmc/core/block.c > +++ b/drivers/mmc/core/block.c > @@ -1426,15 +1426,18 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq, > } > } > > -#define CMD_ERRORS \ > - (R1_OUT_OF_RANGE | /* Command argument out of range */ \ > - R1_ADDRESS_ERROR | /* Misaligned address */ \ > +#define CMD_ERRORS_EXCL_OOR \ > + (R1_ADDRESS_ERROR | /* Misaligned address */ \ > R1_BLOCK_LEN_ERROR | /* Transferred block length incorrect */\ > R1_WP_VIOLATION | /* Tried to write to protected block */ \ > R1_CARD_ECC_FAILED | /* Card ECC failed */ \ > R1_CC_ERROR | /* Card controller error */ \ > R1_ERROR) /* General/unknown error */ > > +#define CMD_ERRORS \ > + (CMD_ERRORS_EXCL_OOR | \ > + R1_OUT_OF_RANGE) /* Command argument out of range */ \ > + > static void mmc_blk_eval_resp_error(struct mmc_blk_request *brq) > { > u32 val; > @@ -1951,6 +1954,95 @@ static void mmc_blk_ss_read(struct mmc_queue *mq, struct request *req) > mqrq->retries = MMC_NO_RETRIES; > } > > +static inline bool mmc_blk_oor_valid(struct mmc_blk_request *brq) > +{ > + return !!brq->mrq.sbc; > +} > + > +static inline u32 mmc_blk_stop_err_bits(struct mmc_blk_request *brq) > +{ > + return mmc_blk_oor_valid(brq) ? CMD_ERRORS : CMD_ERRORS_EXCL_OOR; > +} > + > +static inline bool mmc_blk_in_tran_state(u32 status) > +{ > + /* > + * Some cards mishandle the status bits, so make sure to check both the > + * busy indication and the card state. > + */ > + return status & R1_READY_FOR_DATA && > + (R1_CURRENT_STATE(status) == R1_STATE_TRAN); > +} > + > +static unsigned int mmc_blk_clock_khz(struct mmc_host *host) > +{ > + if (host->actual_clock) > + return host->actual_clock / 1000; > + > + /* Clock may be subject to a divisor, fudge it by a factor of 2. */ > + if (host->ios.clock) > + return host->ios.clock / 2000; > + > + /* How can there be no clock */ > + WARN_ON_ONCE(1); > + return 100; /* 100 kHz is minimum possible value */ > +} > + > +static unsigned long mmc_blk_data_timeout_jiffies(struct mmc_host *host, > + struct mmc_data *data) > +{ > + unsigned int ms = DIV_ROUND_UP(data->timeout_ns, 1000000); > + unsigned int khz; > + > + if (data->timeout_clks) { > + khz = mmc_blk_clock_khz(host); > + ms += DIV_ROUND_UP(data->timeout_clks, khz); > + } > + > + return msecs_to_jiffies(ms); > +} > + > +static int mmc_blk_card_stuck(struct mmc_card *card, struct request *req, > + u32 *resp_errs) > +{ > + struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); > + struct mmc_data *data = &mqrq->brq.data; > + unsigned long timeout; > + u32 status; > + int err; > + > + timeout = jiffies + mmc_blk_data_timeout_jiffies(card->host, data); > + > + while (1) { > + bool done = time_after(jiffies, timeout); > + > + err = __mmc_send_status(card, &status, 5); > + if (err) { > + pr_err("%s: error %d requesting status\n", > + req->rq_disk->disk_name, err); > + break; > + } > + > + /* Accumulate any response error bits seen */ > + if (resp_errs) > + *resp_errs |= status; > + > + if (mmc_blk_in_tran_state(status)) > + break; > + > + /* Timeout if the device never becomes ready */ > + if (done) { > + pr_err("%s: Card stuck in wrong state! %s %s\n", > + mmc_hostname(card->host), > + req->rq_disk->disk_name, __func__); > + err = -ETIMEDOUT; > + break; > + } > + } > + > + return err; > +} The new function here, mmc_blk_card_stuck() looks very similar to card_busy_detect(). Why can't you instead fixup card_busy_detect() so it behaves like the new mmc_blk_card_stuck(), rather than re-implementing most of it? > + > static void mmc_blk_rw_recovery(struct mmc_queue *mq, struct request *req) > { > int type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; > @@ -2097,17 +2189,26 @@ static inline bool mmc_blk_rq_error(struct mmc_blk_request *brq) > static int mmc_blk_card_busy(struct mmc_card *card, struct request *req) > { > struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); > - bool gen_err = false; > + u32 status = 0; > int err; > > if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ) > return 0; > > - err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req, &gen_err); > + err = mmc_blk_card_stuck(card, req, &status); > + > + /* > + * Do not assume data transferred correctly if there are any error bits > + * set. > + */ > + if (!err && status & mmc_blk_stop_err_bits(&mqrq->brq)) { > + mqrq->brq.data.bytes_xfered = 0; > + err = -EIO; > + } > > - /* Copy the general error bit so it will be seen later on */ > - if (gen_err) > - mqrq->brq.stop.resp[0] |= R1_ERROR; > + /* Copy the exception bit so it will be seen later on */ > + if (mmc_card_mmc(card) && status & R1_EXCEPTION_EVENT) > + mqrq->brq.cmd.resp[0] |= R1_EXCEPTION_EVENT; > > return err; > } > -- > 1.9.1 > Kind regards Uffe