From 2086faae3c55a652cfbd369e18ecdb703aacc493 Mon Sep 17 00:00:00 2001 From: Kars de Jong Date: Tue, 19 Nov 2019 21:20:20 +0100 Subject: scsi: esp_scsi: Correct ordering of PCSCSI definition in esp_rev enum The order of the definitions in the esp_rev enum is important. The values are used in comparisons for chip features. Add a comment to the enum explaining this. Also, the actual values for the enum fields are irrelevant, so remove the explicit values (suggested by Geert Uytterhoeven). This makes adding a new field in the middle of the enum easier. Finally, move the PCSCSI definition to the right place in the enum. In its previous location, at the end of the enum, the wrong values are written to the CONFIG3 register when used with FAST-SCSI targets. Link: https://lore.kernel.org/r/20191119202021.28720-2-jongk@linux-m68k.org Signed-off-by: Kars de Jong Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 2 +- drivers/scsi/esp_scsi.h | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index bb88995a12c7..4fc3eee3138b 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2373,10 +2373,10 @@ static const char *esp_chip_names[] = { "ESP100A", "ESP236", "FAS236", + "AM53C974", "FAS100A", "FAST", "FASHME", - "AM53C974", }; static struct scsi_transport_template *esp_transport_template; diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 91b32f2a1a1b..f764d64e1f25 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -257,15 +257,16 @@ struct esp_cmd_priv { }; #define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp)) +/* NOTE: this enum is ordered based on chip features! */ enum esp_rev { - ESP100 = 0x00, /* NCR53C90 - very broken */ - ESP100A = 0x01, /* NCR53C90A */ - ESP236 = 0x02, - FAS236 = 0x03, - FAS100A = 0x04, - FAST = 0x05, - FASHME = 0x06, - PCSCSI = 0x07, /* AM53c974 */ + ESP100, /* NCR53C90 - very broken */ + ESP100A, /* NCR53C90A */ + ESP236, + FAS236, + PCSCSI, /* AM53c974 */ + FAS100A, + FAST, + FASHME, }; struct esp_cmd_entry { -- cgit v1.2.3 From bd40726153c646ed28f830e22a27f5e831b77017 Mon Sep 17 00:00:00 2001 From: Kars de Jong Date: Tue, 19 Nov 2019 21:20:21 +0100 Subject: scsi: esp_scsi: Add support for FSC chip The FSC (NCR53CF9x-2 / SYM53CF9x-2) has a different family code than QLogic or Emulex parts. This caused it to be detected as a FAS100A. Unforunately, this meant the configuration of the CONFIG3 register was incorrect. This causes data transfer issues with FAST-SCSI targets. The FSC also has the CONFIG4 register. It can be used to enable a feature called Active Negation which should always be enabled according to the data manual. Link: https://lore.kernel.org/r/20191119202021.28720-3-jongk@linux-m68k.org Reviewed-by: Finn Thain Signed-off-by: Kars de Jong Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 20 ++++++++++++-------- drivers/scsi/esp_scsi.h | 24 ++++++++++++++++-------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 4fc3eee3138b..89afa31e33cb 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -243,8 +243,6 @@ static void esp_set_all_config3(struct esp *esp, u8 val) /* Reset the ESP chip, _not_ the SCSI bus. */ static void esp_reset_esp(struct esp *esp) { - u8 family_code, version; - /* Now reset the ESP chip */ scsi_esp_cmd(esp, ESP_CMD_RC); scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); @@ -257,14 +255,19 @@ static void esp_reset_esp(struct esp *esp) */ esp->max_period = ((35 * esp->ccycle) / 1000); if (esp->rev == FAST) { - version = esp_read8(ESP_UID); - family_code = (version & 0xf8) >> 3; - if (family_code == 0x02) + u8 family_code = ESP_FAMILY(esp_read8(ESP_UID)); + + if (family_code == ESP_UID_F236) { esp->rev = FAS236; - else if (family_code == 0x0a) + } else if (family_code == ESP_UID_HME) { esp->rev = FASHME; /* Version is usually '5'. */ - else + } else if (family_code == ESP_UID_FSC) { + esp->rev = FSC; + /* Enable Active Negation */ + esp_write8(ESP_CONFIG4_RADE, ESP_CFG4); + } else { esp->rev = FAS100A; + } esp->min_period = ((4 * esp->ccycle) / 1000); } else { esp->min_period = ((5 * esp->ccycle) / 1000); @@ -308,7 +311,7 @@ static void esp_reset_esp(struct esp *esp) case FAS236: case PCSCSI: - /* Fast 236, AM53c974 or HME */ + case FSC: esp_write8(esp->config2, ESP_CFG2); if (esp->rev == FASHME) { u8 cfg3 = esp->target[0].esp_config3; @@ -2374,6 +2377,7 @@ static const char *esp_chip_names[] = { "ESP236", "FAS236", "AM53C974", + "53CF9x-2", "FAS100A", "FAST", "FASHME", diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index f764d64e1f25..446a3d18c022 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -78,12 +78,14 @@ #define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ #define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */ -/* ESP config register 4 read-write, found only on am53c974 chips */ -#define ESP_CONFIG4_RADE 0x04 /* Active negation */ -#define ESP_CONFIG4_RAE 0x08 /* Active negation on REQ and ACK */ -#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature */ -#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 */ -#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 */ +/* ESP config register 4 read-write */ +#define ESP_CONFIG4_BBTE 0x01 /* Back-to-back transfers (fsc) */ +#define ESP_CONGIG4_TEST 0x02 /* Transfer counter test mode (fsc) */ +#define ESP_CONFIG4_RADE 0x04 /* Active negation (am53c974/fsc) */ +#define ESP_CONFIG4_RAE 0x08 /* Act. negation REQ/ACK (am53c974) */ +#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature (am53c974) */ +#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 (am53c974) */ +#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 (am53c974) */ #define ESP_CONFIG_GE_12NS (0) #define ESP_CONFIG_GE_25NS (ESP_CONFIG_GE1) @@ -209,10 +211,15 @@ #define ESP_TEST_TS 0x04 /* Tristate test mode */ /* ESP unique ID register read-only, found on fas236+fas100a only */ +#define ESP_UID_FAM 0xf8 /* ESP family bitmask */ + +#define ESP_FAMILY(uid) (((uid) & ESP_UID_FAM) >> 3) + +/* Values for the ESP family bits */ #define ESP_UID_F100A 0x00 /* ESP FAS100A */ #define ESP_UID_F236 0x02 /* ESP FAS236 */ -#define ESP_UID_REV 0x07 /* ESP revision */ -#define ESP_UID_FAM 0xf8 /* ESP family */ +#define ESP_UID_HME 0x0a /* FAS HME */ +#define ESP_UID_FSC 0x14 /* NCR/Symbios Logic 53CF9x-2 */ /* ESP fifo flags register read-only */ /* Note that the following implies a 16 byte FIFO on the ESP. */ @@ -264,6 +271,7 @@ enum esp_rev { ESP236, FAS236, PCSCSI, /* AM53c974 */ + FSC, /* NCR/Symbios Logic 53CF9x-2 */ FAS100A, FAST, FASHME, -- cgit v1.2.3 From 7252a3603015f1fd04363956f4b72a537c9f9c42 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 9 Dec 2019 10:13:08 -0800 Subject: scsi: ufs: Avoid busy-waiting by eliminating tag conflicts Instead of tracking which tags are in use in the ufs_hba.lrb_in_use bitmask, rely on the block layer tag allocation mechanism. This patch removes the following busy-waiting loop if ufshcd_issue_devman_upiu_cmd() and the block layer accidentally allocate the same tag for a SCSI request: * ufshcd_queuecommand() returns SCSI_MLQUEUE_HOST_BUSY. * The SCSI core requeues the SCSI command. Cc: Can Guo Cc: Stanley Chu Cc: Avri Altman Cc: Tomas Winkler Link: https://lore.kernel.org/r/20191209181309.196233-2-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Avri Altman Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 121 ++++++++++++++++++---------------------------- drivers/scsi/ufs/ufshcd.h | 6 +-- 2 files changed, 50 insertions(+), 77 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b5966faf3e98..18f197e76ce3 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -497,8 +497,8 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap) static void ufshcd_print_host_state(struct ufs_hba *hba) { dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state); - dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx tasks=0x%lx\n", - hba->lrb_in_use, hba->outstanding_reqs, hba->outstanding_tasks); + dev_err(hba->dev, "outstanding reqs=0x%lx tasks=0x%lx\n", + hba->outstanding_reqs, hba->outstanding_tasks); dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n", hba->saved_err, hba->saved_uic_err); dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n", @@ -1273,6 +1273,24 @@ out: return ret; } +static bool ufshcd_is_busy(struct request *req, void *priv, bool reserved) +{ + int *busy = priv; + + WARN_ON_ONCE(reserved); + (*busy)++; + return false; +} + +/* Whether or not any tag is in use by a request that is in progress. */ +static bool ufshcd_any_tag_in_use(struct ufs_hba *hba) +{ + struct request_queue *q = hba->cmd_queue; + int busy = 0; + + blk_mq_tagset_busy_iter(q->tag_set, ufshcd_is_busy, &busy); + return busy; +} static int ufshcd_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) @@ -1619,7 +1637,7 @@ static void ufshcd_gate_work(struct work_struct *work) if (hba->clk_gating.active_reqs || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL - || hba->lrb_in_use || hba->outstanding_tasks + || ufshcd_any_tag_in_use(hba) || hba->outstanding_tasks || hba->active_uic_cmd || hba->uic_async_done) goto rel_lock; @@ -1673,7 +1691,7 @@ static void __ufshcd_release(struct ufs_hba *hba) if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL - || hba->lrb_in_use || hba->outstanding_tasks + || ufshcd_any_tag_in_use(hba) || hba->outstanding_tasks || hba->active_uic_cmd || hba->uic_async_done || ufshcd_eh_in_progress(hba)) return; @@ -2443,22 +2461,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) hba->req_abort_count = 0; - /* acquire the tag to make sure device cmds don't use it */ - if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) { - /* - * Dev manage command in progress, requeue the command. - * Requeuing the command helps in cases where the request *may* - * find different tag instead of waiting for dev manage command - * completion. - */ - err = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - err = ufshcd_hold(hba, true); if (err) { err = SCSI_MLQUEUE_HOST_BUSY; - clear_bit_unlock(tag, &hba->lrb_in_use); goto out; } WARN_ON(hba->clk_gating.state != CLKS_ON); @@ -2479,7 +2484,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) err = ufshcd_map_sg(hba, lrbp); if (err) { lrbp->cmd = NULL; - clear_bit_unlock(tag, &hba->lrb_in_use); goto out; } /* Make sure descriptors are ready before ringing the doorbell */ @@ -2626,44 +2630,6 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, return err; } -/** - * ufshcd_get_dev_cmd_tag - Get device management command tag - * @hba: per-adapter instance - * @tag_out: pointer to variable with available slot value - * - * Get a free slot and lock it until device management command - * completes. - * - * Returns false if free slot is unavailable for locking, else - * return true with tag value in @tag. - */ -static bool ufshcd_get_dev_cmd_tag(struct ufs_hba *hba, int *tag_out) -{ - int tag; - bool ret = false; - unsigned long tmp; - - if (!tag_out) - goto out; - - do { - tmp = ~hba->lrb_in_use; - tag = find_last_bit(&tmp, hba->nutrs); - if (tag >= hba->nutrs) - goto out; - } while (test_and_set_bit_lock(tag, &hba->lrb_in_use)); - - *tag_out = tag; - ret = true; -out: - return ret; -} - -static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag) -{ - clear_bit_unlock(tag, &hba->lrb_in_use); -} - /** * ufshcd_exec_dev_cmd - API for sending device management requests * @hba: UFS hba @@ -2676,6 +2642,8 @@ static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag) static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, int timeout) { + struct request_queue *q = hba->cmd_queue; + struct request *req; struct ufshcd_lrb *lrbp; int err; int tag; @@ -2689,7 +2657,11 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, * Even though we use wait_event() which sleeps indefinitely, * the maximum wait time is bounded by SCSI request timeout. */ - wait_event(hba->dev_cmd.tag_wq, ufshcd_get_dev_cmd_tag(hba, &tag)); + req = blk_get_request(q, REQ_OP_DRV_OUT, 0); + if (IS_ERR(req)) + return PTR_ERR(req); + tag = req->tag; + WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag)); init_completion(&wait); lrbp = &hba->lrb[tag]; @@ -2714,8 +2686,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, err ? "query_complete_err" : "query_complete"); out_put_tag: - ufshcd_put_dev_cmd_tag(hba, tag); - wake_up(&hba->dev_cmd.tag_wq); + blk_put_request(req); up_read(&hba->clk_scaling_lock); return err; } @@ -4856,7 +4827,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, cmd->result = result; /* Mark completed command as NULL in LRB */ lrbp->cmd = NULL; - clear_bit_unlock(index, &hba->lrb_in_use); /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); __ufshcd_release(hba); @@ -4878,9 +4848,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, hba->outstanding_reqs ^= completed_reqs; ufshcd_clk_scaling_update_busy(hba); - - /* we might have free'd some tags above */ - wake_up(&hba->dev_cmd.tag_wq); } /** @@ -5863,6 +5830,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, enum query_opcode desc_op) { + struct request_queue *q = hba->cmd_queue; + struct request *req; struct ufshcd_lrb *lrbp; int err = 0; int tag; @@ -5872,7 +5841,11 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, down_read(&hba->clk_scaling_lock); - wait_event(hba->dev_cmd.tag_wq, ufshcd_get_dev_cmd_tag(hba, &tag)); + req = blk_get_request(q, REQ_OP_DRV_OUT, 0); + if (IS_ERR(req)) + return PTR_ERR(req); + tag = req->tag; + WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag)); init_completion(&wait); lrbp = &hba->lrb[tag]; @@ -5948,8 +5921,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, } } - ufshcd_put_dev_cmd_tag(hba, tag); - wake_up(&hba->dev_cmd.tag_wq); + blk_put_request(req); up_read(&hba->clk_scaling_lock); return err; } @@ -6244,9 +6216,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) hba->lrb[tag].cmd = NULL; spin_unlock_irqrestore(host->host_lock, flags); - clear_bit_unlock(tag, &hba->lrb_in_use); - wake_up(&hba->dev_cmd.tag_wq); - out: if (!err) { err = SUCCESS; @@ -8250,6 +8219,7 @@ void ufshcd_remove(struct ufs_hba *hba) { ufs_bsg_remove(hba); ufs_sysfs_remove_nodes(hba->dev); + blk_cleanup_queue(hba->cmd_queue); scsi_remove_host(hba->host); /* disable interrupts */ ufshcd_disable_intr(hba, hba->intr_mask); @@ -8413,9 +8383,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) init_rwsem(&hba->clk_scaling_lock); - /* Initialize device management tag acquire wait queue */ - init_waitqueue_head(&hba->dev_cmd.tag_wq); - ufshcd_init_clk_gating(hba); ufshcd_init_clk_scaling(hba); @@ -8449,6 +8416,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto exit_gating; } + hba->cmd_queue = blk_mq_init_queue(&hba->host->tag_set); + if (IS_ERR(hba->cmd_queue)) { + err = PTR_ERR(hba->cmd_queue); + goto out_remove_scsi_host; + } + /* Reset the attached device */ ufshcd_vops_device_reset(hba); @@ -8458,7 +8431,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) dev_err(hba->dev, "Host controller enable failed\n"); ufshcd_print_host_regs(hba); ufshcd_print_host_state(hba); - goto out_remove_scsi_host; + goto free_cmd_queue; } /* @@ -8495,6 +8468,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) return 0; +free_cmd_queue: + blk_cleanup_queue(hba->cmd_queue); out_remove_scsi_host: scsi_remove_host(hba->host); exit_gating: diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 2740f6941ec6..56b9da6db1cc 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -212,13 +212,11 @@ struct ufs_query { * @type: device management command type - Query, NOP OUT * @lock: lock to allow one command at a time * @complete: internal commands completion - * @tag_wq: wait queue until free command slot is available */ struct ufs_dev_cmd { enum dev_cmd_type type; struct mutex lock; struct completion *complete; - wait_queue_head_t tag_wq; struct ufs_query query; }; @@ -483,7 +481,7 @@ struct ufs_stats { * @host: Scsi_Host instance of the driver * @dev: device handle * @lrb: local reference block - * @lrb_in_use: lrb in use + * @cmd_queue: Used to allocate command tags from hba->host->tag_set. * @outstanding_tasks: Bits representing outstanding task requests * @outstanding_reqs: Bits representing outstanding transfer requests * @capabilities: UFS Controller Capabilities @@ -541,6 +539,7 @@ struct ufs_hba { struct Scsi_Host *host; struct device *dev; + struct request_queue *cmd_queue; /* * This field is to keep a reference to "scsi_device" corresponding to * "UFS device" W-LU. @@ -561,7 +560,6 @@ struct ufs_hba { u32 ahit; struct ufshcd_lrb *lrb; - unsigned long lrb_in_use; unsigned long outstanding_tasks; unsigned long outstanding_reqs; -- cgit v1.2.3 From 69a6c269c097d780a2db320ecd47f7a62fafd92e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 9 Dec 2019 10:13:09 -0800 Subject: scsi: ufs: Use blk_{get,put}_request() to allocate and free TMFs Manage TMF tags with blk_{get,put}_request() instead of ufshcd_get_tm_free_slot() / ufshcd_put_tm_slot(). Store a per-request completion pointer in request.end_io_data instead of using a waitqueue to report TMF completion. Cc: Can Guo Cc: Stanley Chu Cc: Avri Altman Cc: Tomas Winkler Link: https://lore.kernel.org/r/20191209181309.196233-3-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Avri Altman Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 130 +++++++++++++++++++++++++++------------------- drivers/scsi/ufs/ufshcd.h | 12 ++--- 2 files changed, 80 insertions(+), 62 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 18f197e76ce3..b9a9ec8de019 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -645,40 +645,6 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp) return le32_to_cpu(lrbp->utr_descriptor_ptr->header.dword_2) & MASK_OCS; } -/** - * ufshcd_get_tm_free_slot - get a free slot for task management request - * @hba: per adapter instance - * @free_slot: pointer to variable with available slot value - * - * Get a free tag and lock it until ufshcd_put_tm_slot() is called. - * Returns 0 if free slot is not available, else return 1 with tag value - * in @free_slot. - */ -static bool ufshcd_get_tm_free_slot(struct ufs_hba *hba, int *free_slot) -{ - int tag; - bool ret = false; - - if (!free_slot) - goto out; - - do { - tag = find_first_zero_bit(&hba->tm_slots_in_use, hba->nutmrs); - if (tag >= hba->nutmrs) - goto out; - } while (test_and_set_bit_lock(tag, &hba->tm_slots_in_use)); - - *free_slot = tag; - ret = true; -out: - return ret; -} - -static inline void ufshcd_put_tm_slot(struct ufs_hba *hba, int slot) -{ - clear_bit_unlock(slot, &hba->tm_slots_in_use); -} - /** * ufshcd_utrl_clear - Clear a bit in UTRLCLR register * @hba: per adapter instance @@ -5570,6 +5536,27 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) return retval; } +struct ctm_info { + struct ufs_hba *hba; + unsigned long pending; + unsigned int ncpl; +}; + +static bool ufshcd_compl_tm(struct request *req, void *priv, bool reserved) +{ + struct ctm_info *const ci = priv; + struct completion *c; + + WARN_ON_ONCE(reserved); + if (test_bit(req->tag, &ci->pending)) + return true; + ci->ncpl++; + c = req->end_io_data; + if (c) + complete(c); + return true; +} + /** * ufshcd_tmc_handler - handle task management function completion * @hba: per adapter instance @@ -5580,16 +5567,14 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) */ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba) { - u32 tm_doorbell; + struct request_queue *q = hba->tmf_queue; + struct ctm_info ci = { + .hba = hba, + .pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL), + }; - tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL); - hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks; - if (hba->tm_condition) { - wake_up(&hba->tm_wq); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } + blk_mq_tagset_busy_iter(q->tag_set, ufshcd_compl_tm, &ci); + return ci.ncpl ? IRQ_HANDLED : IRQ_NONE; } /** @@ -5695,7 +5680,10 @@ out: static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, struct utp_task_req_desc *treq, u8 tm_function) { + struct request_queue *q = hba->tmf_queue; struct Scsi_Host *host = hba->host; + DECLARE_COMPLETION_ONSTACK(wait); + struct request *req; unsigned long flags; int free_slot, task_tag, err; @@ -5704,7 +5692,10 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, * Even though we use wait_event() which sleeps indefinitely, * the maximum wait time is bounded by %TM_CMD_TIMEOUT. */ - wait_event(hba->tm_tag_wq, ufshcd_get_tm_free_slot(hba, &free_slot)); + req = blk_get_request(q, REQ_OP_DRV_OUT, BLK_MQ_REQ_RESERVED); + req->end_io_data = &wait; + free_slot = req->tag; + WARN_ON_ONCE(free_slot < 0 || free_slot >= hba->nutmrs); ufshcd_hold(hba, false); spin_lock_irqsave(host->host_lock, flags); @@ -5730,10 +5721,14 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_send"); /* wait until the task management command is completed */ - err = wait_event_timeout(hba->tm_wq, - test_bit(free_slot, &hba->tm_condition), + err = wait_for_completion_io_timeout(&wait, msecs_to_jiffies(TM_CMD_TIMEOUT)); if (!err) { + /* + * Make sure that ufshcd_compl_tm() does not trigger a + * use-after-free. + */ + req->end_io_data = NULL; ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete_err"); dev_err(hba->dev, "%s: task management cmd 0x%.2x timed-out\n", __func__, tm_function); @@ -5752,9 +5747,7 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, __clear_bit(free_slot, &hba->outstanding_tasks); spin_unlock_irqrestore(hba->host->host_lock, flags); - clear_bit(free_slot, &hba->tm_condition); - ufshcd_put_tm_slot(hba, free_slot); - wake_up(&hba->tm_tag_wq); + blk_put_request(req); ufshcd_release(hba); return err; @@ -8219,6 +8212,8 @@ void ufshcd_remove(struct ufs_hba *hba) { ufs_bsg_remove(hba); ufs_sysfs_remove_nodes(hba->dev); + blk_cleanup_queue(hba->tmf_queue); + blk_mq_free_tag_set(&hba->tmf_tag_set); blk_cleanup_queue(hba->cmd_queue); scsi_remove_host(hba->host); /* disable interrupts */ @@ -8298,6 +8293,18 @@ out_error: } EXPORT_SYMBOL(ufshcd_alloc_host); +/* This function exists because blk_mq_alloc_tag_set() requires this. */ +static blk_status_t ufshcd_queue_tmf(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *qd) +{ + WARN_ON_ONCE(true); + return BLK_STS_NOTSUPP; +} + +static const struct blk_mq_ops ufshcd_tmf_ops = { + .queue_rq = ufshcd_queue_tmf, +}; + /** * ufshcd_init - Driver initialization routine * @hba: per-adapter instance @@ -8367,10 +8374,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->max_pwr_info.is_valid = false; - /* Initailize wait queue for task management */ - init_waitqueue_head(&hba->tm_wq); - init_waitqueue_head(&hba->tm_tag_wq); - /* Initialize work queues */ INIT_WORK(&hba->eh_work, ufshcd_err_handler); INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler); @@ -8422,6 +8425,21 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto out_remove_scsi_host; } + hba->tmf_tag_set = (struct blk_mq_tag_set) { + .nr_hw_queues = 1, + .queue_depth = hba->nutmrs, + .ops = &ufshcd_tmf_ops, + .flags = BLK_MQ_F_NO_SCHED, + }; + err = blk_mq_alloc_tag_set(&hba->tmf_tag_set); + if (err < 0) + goto free_cmd_queue; + hba->tmf_queue = blk_mq_init_queue(&hba->tmf_tag_set); + if (IS_ERR(hba->tmf_queue)) { + err = PTR_ERR(hba->tmf_queue); + goto free_tmf_tag_set; + } + /* Reset the attached device */ ufshcd_vops_device_reset(hba); @@ -8431,7 +8449,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) dev_err(hba->dev, "Host controller enable failed\n"); ufshcd_print_host_regs(hba); ufshcd_print_host_state(hba); - goto free_cmd_queue; + goto free_tmf_queue; } /* @@ -8468,6 +8486,10 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) return 0; +free_tmf_queue: + blk_cleanup_queue(hba->tmf_queue); +free_tmf_tag_set: + blk_mq_free_tag_set(&hba->tmf_tag_set); free_cmd_queue: blk_cleanup_queue(hba->cmd_queue); out_remove_scsi_host: diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 56b9da6db1cc..53bfe175342c 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -493,11 +493,9 @@ struct ufs_stats { * @irq: Irq number of the controller * @active_uic_cmd: handle of active UIC command * @uic_cmd_mutex: mutex for uic command - * @tm_wq: wait queue for task management - * @tm_tag_wq: wait queue for free task management slots - * @tm_slots_in_use: bit map of task management request slots in use + * @tmf_tag_set: TMF tag set. + * @tmf_queue: Used to allocate TMF tags. * @pwr_done: completion for power mode change - * @tm_condition: condition variable for task management * @ufshcd_state: UFSHCD states * @eh_flags: Error handling flags * @intr_mask: Interrupt Mask Bits @@ -641,10 +639,8 @@ struct ufs_hba { /* Device deviations from standard UFS device spec. */ unsigned int dev_quirks; - wait_queue_head_t tm_wq; - wait_queue_head_t tm_tag_wq; - unsigned long tm_condition; - unsigned long tm_slots_in_use; + struct blk_mq_tag_set tmf_tag_set; + struct request_queue *tmf_queue; struct uic_command *active_uic_cmd; struct mutex uic_cmd_mutex; -- cgit v1.2.3 From 24366c2afbb0539fb14eff330d4e3a5db5c0a3ef Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Mon, 25 Nov 2019 22:53:30 -0800 Subject: scsi: ufs: Recheck bkops level if bkops is disabled bkops level should be rechecked upon receiving an exception. Currently the level is being cached and never updated. Update bkops each time the level is checked. Also do not use the cached bkops level value if it is disabled and then enabled. Fixes: afdfff59a0e0 (scsi: ufs: handle non spec compliant bkops behaviour by device) Link: https://lore.kernel.org/r/1574751214-8321-2-git-send-email-cang@qti.qualcomm.com Reviewed-by: Bean Huo Reviewed-by: Alim Akhtar Tested-by: Alim Akhtar Signed-off-by: Asutosh Das Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b9a9ec8de019..839cb7badcf6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4986,6 +4986,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) hba->auto_bkops_enabled = false; trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Disabled"); + hba->is_urgent_bkops_lvl_checked = false; out: return err; } @@ -5010,6 +5011,7 @@ static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba) hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS; ufshcd_disable_auto_bkops(hba); } + hba->is_urgent_bkops_lvl_checked = false; } static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status) @@ -5056,6 +5058,7 @@ static int ufshcd_bkops_ctrl(struct ufs_hba *hba, err = ufshcd_enable_auto_bkops(hba); else err = ufshcd_disable_auto_bkops(hba); + hba->urgent_bkops_lvl = curr_status; out: return err; } -- cgit v1.2.3 From a7ef6f029a7658f2d9b9a78b3b1d8f4cb981bbdf Mon Sep 17 00:00:00 2001 From: Can Guo Date: Mon, 25 Nov 2019 22:53:31 -0800 Subject: scsi: ufs: Update VCCQ2 and VCCQ min/max voltage hard codes Per UFS 3.0 JEDEC standard, the VCCQ2 min voltage is 1.7v and the VCCQ voltage range is 1.14v ~ 1.26v. Update their hard codes accordingly to make sure they work in a safe range compliant for ver 1.0/1.1/2.0/2.1/3.0 UFS devices. Link: https://lore.kernel.org/r/1574751214-8321-3-git-send-email-cang@qti.qualcomm.com Reviewed-by: Bean Huo Reviewed-by: Avri Altman Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 3327981ef894..c89f21698629 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -499,9 +499,9 @@ struct ufs_query_res { #define UFS_VREG_VCC_MAX_UV 3600000 /* uV */ #define UFS_VREG_VCC_1P8_MIN_UV 1700000 /* uV */ #define UFS_VREG_VCC_1P8_MAX_UV 1950000 /* uV */ -#define UFS_VREG_VCCQ_MIN_UV 1100000 /* uV */ -#define UFS_VREG_VCCQ_MAX_UV 1300000 /* uV */ -#define UFS_VREG_VCCQ2_MIN_UV 1650000 /* uV */ +#define UFS_VREG_VCCQ_MIN_UV 1140000 /* uV */ +#define UFS_VREG_VCCQ_MAX_UV 1260000 /* uV */ +#define UFS_VREG_VCCQ2_MIN_UV 1700000 /* uV */ #define UFS_VREG_VCCQ2_MAX_UV 1950000 /* uV */ /* -- cgit v1.2.3 From 74a527a2ab1c5c09f7bf37cfb00a93b6d75fbda7 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Mon, 25 Nov 2019 22:53:32 -0800 Subject: scsi: ufs: Avoid messing up the compl_time_stamp of lrbs To be on the safe side, do not touch lrb after clearing its slot in the lrb_in_use bitmap to avoid messing up the next task which would possibly occupy this lrb. [mkp: applied by hand] Link: https://lore.kernel.org/r/1574751214-8321-4-git-send-email-cang@qti.qualcomm.com Reviewed by: Avri Altman Reviewed-by: Bean Huo Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 839cb7badcf6..e91dc574a08a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4793,11 +4793,13 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, cmd->result = result; /* Mark completed command as NULL in LRB */ lrbp->cmd = NULL; + lrbp->compl_time_stamp = ktime_get(); /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); __ufshcd_release(hba); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { + lrbp->compl_time_stamp = ktime_get(); if (hba->dev_cmd.complete) { ufshcd_add_command_trace(hba, index, "dev_complete"); @@ -4806,8 +4808,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, } if (ufshcd_is_clkscaling_supported(hba)) hba->clk_scaling.active_reqs--; - - lrbp->compl_time_stamp = ktime_get(); } /* clear corresponding bits of completed commands */ -- cgit v1.2.3 From 2df74b6985b51e77756e2e8faa16c45ca3ba53c5 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Mon, 25 Nov 2019 22:53:33 -0800 Subject: scsi: ufs: Complete pending requests in host reset and restore path In UFS host reset and restore path, before probe, we stop and start the host controller once. After host controller is stopped, the pending requests, if any, are cleared from the doorbell, but no completion IRQ would be raised due to the hba is stopped. These pending requests shall be completed along with the first NOP_OUT command (as it is the first command which can raise a transfer completion IRQ) sent during probe. Since the OCSs of these pending requests are not SUCCESS (because they are not yet literally finished), their UPIUs shall be dumped. When there are multiple pending requests, the UPIU dump can be overwhelming and may lead to stability issues because it is in atomic context. Therefore, before probe, complete these pending requests right after host controller is stopped and silence the UPIU dump from them. Link: https://lore.kernel.org/r/1574751214-8321-5-git-send-email-cang@qti.qualcomm.com Reviewed-by: Alim Akhtar Reviewed-by: Bean Huo Tested-by: Bean Huo Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 24 ++++++++++-------------- drivers/scsi/ufs/ufshcd.h | 2 ++ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e91dc574a08a..bd2ce2d4823f 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4736,7 +4736,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) break; } /* end of switch */ - if (host_byte(result) != DID_OK) + if ((host_byte(result) != DID_OK) && !hba->silence_err_logs) ufshcd_print_trs(hba, 1 << lrbp->task_tag, true); return result; } @@ -5284,8 +5284,8 @@ static void ufshcd_err_handler(struct work_struct *work) /* * if host reset is required then skip clearing the pending - * transfers forcefully because they will automatically get - * cleared after link startup. + * transfers forcefully because they will get cleared during + * host reset and restore */ if (needs_reset) goto skip_pending_xfer_clear; @@ -6244,9 +6244,15 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) int err; unsigned long flags; - /* Reset the host controller */ + /* + * Stop the host controller and complete the requests + * cleared by h/w + */ spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_hba_stop(hba, false); + hba->silence_err_logs = true; + ufshcd_complete_requests(hba); + hba->silence_err_logs = false; spin_unlock_irqrestore(hba->host->host_lock, flags); /* scale up clocks to max frequency before full reinitialization */ @@ -6280,7 +6286,6 @@ out: static int ufshcd_reset_and_restore(struct ufs_hba *hba) { int err = 0; - unsigned long flags; int retries = MAX_HOST_RESET_RETRIES; do { @@ -6290,15 +6295,6 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) err = ufshcd_host_reset_and_restore(hba); } while (err && --retries); - /* - * After reset the door-bell might be cleared, complete - * outstanding requests in s/w here. - */ - spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_transfer_req_compl(hba); - ufshcd_tmc_handler(hba); - spin_unlock_irqrestore(hba->host->host_lock, flags); - return err; } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 53bfe175342c..b536a26d665e 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -509,6 +509,7 @@ struct ufs_stats { * @uic_error: UFS interconnect layer error status * @saved_err: sticky error mask * @saved_uic_err: sticky UIC error mask + * @silence_err_logs: flag to silence error logs * @dev_cmd: ufs device management command information * @last_dme_cmd_tstamp: time stamp of the last completed DME command * @auto_bkops_enabled: to track whether bkops is enabled in device @@ -664,6 +665,7 @@ struct ufs_hba { u32 saved_err; u32 saved_uic_err; struct ufs_stats ufs_stats; + bool silence_err_logs; /* Device management request data */ struct ufs_dev_cmd dev_cmd; -- cgit v1.2.3 From 0ec96913344de9efdb388720247ea9f207bdc3aa Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 5 Dec 2019 02:14:25 +0000 Subject: scsi: core: Adjust DBD setting in MODE SENSE for caching mode page per LLD UFS JEDEC standards require DBD field to be set to 1 in mode sense command. This patch allows LLD to define the setting of DBD, if required. Link: https://lore.kernel.org/r/0101016ed3d643f9-ffd45d6c-c593-4a13-a18f-a32da3d3bb97-000000@us-west-2.amazonses.com Reviewed-by: Avri Altman Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 2 ++ include/scsi/scsi_device.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3e7a45d0daca..610ee41fa54c 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2108,6 +2108,8 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, memset(data, 0, sizeof(*data)); memset(&cmd[0], 0, 12); + + dbd = sdev->set_dbd_for_ms ? 8 : dbd; cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ cmd[2] = modepage; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 3ed836db5306..f8312a3e5b42 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -172,6 +172,7 @@ struct scsi_device { * because we did a bus reset. */ unsigned use_10_for_rw:1; /* first try 10-byte read / write */ unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ + unsigned set_dbd_for_ms:1; /* Set "DBD" field in mode sense */ unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ unsigned no_write_same:1; /* no WRITE SAME command */ unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */ -- cgit v1.2.3 From a3a763917216992b8b1b2cc1b4fadb27c660fe70 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 5 Dec 2019 02:14:30 +0000 Subject: scsi: ufs: Use DBD setting in mode sense UFS standard requires DBD field to be set to 1 in MODE SENSE(10). Some card vendors are more strict and check the DBD field, hence respond with CHECK_CONDITION (Sense key set to ILLEGAL_REQUEST and ASC set to INVALID FIELD IN CDB). When host sends MODE SENSE for page caching, as a result of the CHECK_CONDITION response, host assumes that the device doesn't support the cache feature and doesn't send SYNCHRONIZE_CACHE commands to flush the device cache. This can result in data corruption in case of sudden power down when there is data stored in the device cache. This patch fixes the DBD field setting as required in UFS standard. Link: https://lore.kernel.org/r/0101016ed3d657e4-32a6dd52-1505-4312-97ff-2bd3bee59eb7-000000@us-west-2.amazonses.com Reviewed-by: Bean Huo Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index bd2ce2d4823f..0aa42b68dab6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4545,6 +4545,9 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) /* Mode sense(6) is not supported by UFS, so use Mode sense(10) */ sdev->use_10_for_ms = 1; + /* DBD field should be set to 1 in mode sense(10) */ + sdev->set_dbd_for_ms = 1; + /* allow SCSI layer to restart the device in case of errors */ sdev->allow_restart = 1; -- cgit v1.2.3 From 17c7d35f141ef6158076adf3338f115f64fcf760 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 5 Dec 2019 02:14:33 +0000 Subject: scsi: ufs: Release clock if DMA map fails In queuecommand path, if DMA map fails, it bails out with clock held. In this case, release the clock to keep its usage paired. [mkp: applied by hand] Link: https://lore.kernel.org/r/0101016ed3d66395-1b7e7fce-b74d-42ca-a88a-4db78b795d3b-000000@us-west-2.amazonses.com Reviewed-by: Bean Huo Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0aa42b68dab6..64abb30d990a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2450,6 +2450,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) err = ufshcd_map_sg(hba, lrbp); if (err) { lrbp->cmd = NULL; + ufshcd_release(hba); goto out; } /* Make sure descriptors are ready before ringing the doorbell */ -- cgit v1.2.3 From 0834253734cbb40c312c06e5beb9b94ac7cf5e80 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 5 Dec 2019 02:14:42 +0000 Subject: scsi: ufs: Do not clear the DL layer timers During power mode change, PACP_PWR_Req frame sends PAPowerModeUserData parameters (and they are considered valid by device if Flags[4] - UserDataValid bit is set in the same frame). Currently we don't set these PAPowerModeUserData parameters and hardware always sets UserDataValid bit which would clear all the DL layer timeout values of the peer device after the power mode change. This change sets the PAPowerModeUserData[0..5] to UniPro specification recommended default values, in addition we are also setting the relevant DME_LOCAL_* timer attributes as required by UFS HCI specification. Link: https://lore.kernel.org/r/0101016ed3d688a4-cfaeb1c9-238b-46c4-9c89-d48c410ba325-000000@us-west-2.amazonses.com Reviewed-by: Avri Altman Reviewed-by: Bean Huo Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 20 ++++++++++++++++++++ drivers/scsi/ufs/unipro.h | 11 +++++++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 64abb30d990a..c1f92ee5391a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4033,6 +4033,26 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), pwr_mode->hs_rate); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), + DL_FC0ProtectionTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), + DL_TC0ReplayTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), + DL_AFC0ReqTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA3), + DL_FC1ProtectionTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA4), + DL_TC1ReplayTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA5), + DL_AFC1ReqTimeOutVal_Default); + + ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalFC0ProtectionTimeOutVal), + DL_FC0ProtectionTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalTC0ReplayTimeOutVal), + DL_TC0ReplayTimeOutVal_Default); + ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal), + DL_AFC0ReqTimeOutVal_Default); + ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 | pwr_mode->pwr_tx); diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index f539f873f94d..3dc4d8b76509 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -161,6 +161,17 @@ /* PHY Adapter Protocol Constants */ #define PA_MAXDATALANES 4 +#define DL_FC0ProtectionTimeOutVal_Default 8191 +#define DL_TC0ReplayTimeOutVal_Default 65535 +#define DL_AFC0ReqTimeOutVal_Default 32767 +#define DL_FC1ProtectionTimeOutVal_Default 8191 +#define DL_TC1ReplayTimeOutVal_Default 65535 +#define DL_AFC1ReqTimeOutVal_Default 32767 + +#define DME_LocalFC0ProtectionTimeOutVal 0xD041 +#define DME_LocalTC0ReplayTimeOutVal 0xD042 +#define DME_LocalAFC0ReqTimeOutVal 0xD043 + /* PA power modes */ enum { FAST_MODE = 1, -- cgit v1.2.3 From 5231d38c16f0896171b45133d4ea6f6bc6610c82 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 5 Dec 2019 02:14:46 +0000 Subject: scsi: ufs: Do not free irq in suspend Since ufshcd irq resource is allocated with the device resource management aware IRQ request implementation, we don't really need to free up irq during suspend, disabling it during suspend and reenabling it during resume should be good enough. Link: https://lore.kernel.org/r/0101016ed3d69793-22918f99-23bf-495d-8a36-a9c108d1cbce-000000@us-west-2.amazonses.com Reviewed-by: Stanley Chu Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c1f92ee5391a..e5cd57e68c46 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -266,26 +266,18 @@ static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag) return tag >= 0 && tag < hba->nutrs; } -static inline int ufshcd_enable_irq(struct ufs_hba *hba) +static inline void ufshcd_enable_irq(struct ufs_hba *hba) { - int ret = 0; - if (!hba->is_irq_enabled) { - ret = request_irq(hba->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, - hba); - if (ret) - dev_err(hba->dev, "%s: request_irq failed, ret=%d\n", - __func__, ret); + enable_irq(hba->irq); hba->is_irq_enabled = true; } - - return ret; } static inline void ufshcd_disable_irq(struct ufs_hba *hba) { if (hba->is_irq_enabled) { - free_irq(hba->irq, hba); + disable_irq(hba->irq); hba->is_irq_enabled = false; } } @@ -7959,9 +7951,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto out; /* enable the host irq as host controller would be active soon */ - ret = ufshcd_enable_irq(hba); - if (ret) - goto disable_irq_and_vops_clks; + ufshcd_enable_irq(hba); ret = ufshcd_vreg_set_hpm(hba); if (ret) -- cgit v1.2.3 From fc0a9de2f40dc7efe9daf411efc1436811403402 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Thu, 5 Dec 2019 23:09:12 +0100 Subject: scsi: ufs: delete unused structure filed tr Delete unused structure field tr in structure utp_upiu_req, since no person uses it for task management. Fixes: df032bf27a41 ("scsi: ufs: Add a bsg endpoint that supports UPIUs") Link: https://lore.kernel.org/r/20191205220912.5696-1-huobean@gmail.com Reviewed-by: Avri Altman Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_ufs.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 9988db6ad244..d55f2176dfd4 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -68,14 +68,13 @@ struct utp_upiu_cmd { * @header:UPIU header structure DW-0 to DW-2 * @sc: fields structure for scsi command DW-3 to DW-7 * @qr: fields structure for query request DW-3 to DW-7 + * @uc: use utp_upiu_query to host the 4 dwords of uic command */ struct utp_upiu_req { struct utp_upiu_header header; union { struct utp_upiu_cmd sc; struct utp_upiu_query qr; - struct utp_upiu_query tr; - /* use utp_upiu_query to host the 4 dwords of uic command */ struct utp_upiu_query uc; }; }; -- cgit v1.2.3 From e89fbc7feb0013b4ec8145c726c44ded56065216 Mon Sep 17 00:00:00 2001 From: Sheeba B Date: Fri, 6 Dec 2019 05:25:03 +0100 Subject: scsi: ufs: Update L4 attributes on manual hibern8 exit in Cadence UFS. Backup L4 attributes duirng manual hibern8 entry and restore the L4 attributes on manual hibern8 exit as per JESD220C. Link: https://lore.kernel.org/r/1575606303-10917-1-git-send-email-sheebab@cadence.com Reviewed-by: Alim Akhtar Tested-by: Vignesh Raghavendra Signed-off-by: Sheeba B Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/cdns-pltfrm.c | 106 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index 6feeb0faf123..1c80f9633da6 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -19,6 +19,85 @@ #define CDNS_UFS_REG_HCLKDIV 0xFC #define CDNS_UFS_REG_PHY_XCFGD1 0x113C +#define CDNS_UFS_MAX_L4_ATTRS 12 + +struct cdns_ufs_host { + /** + * cdns_ufs_dme_attr_val - for storing L4 attributes + */ + u32 cdns_ufs_dme_attr_val[CDNS_UFS_MAX_L4_ATTRS]; +}; + +/** + * cdns_ufs_get_l4_attr - get L4 attributes on local side + * @hba: per adapter instance + * + */ +static void cdns_ufs_get_l4_attr(struct ufs_hba *hba) +{ + struct cdns_ufs_host *host = ufshcd_get_variant(hba); + + ufshcd_dme_get(hba, UIC_ARG_MIB(T_PEERDEVICEID), + &host->cdns_ufs_dme_attr_val[0]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_PEERCPORTID), + &host->cdns_ufs_dme_attr_val[1]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_TRAFFICCLASS), + &host->cdns_ufs_dme_attr_val[2]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_PROTOCOLID), + &host->cdns_ufs_dme_attr_val[3]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_CPORTFLAGS), + &host->cdns_ufs_dme_attr_val[4]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_TXTOKENVALUE), + &host->cdns_ufs_dme_attr_val[5]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_RXTOKENVALUE), + &host->cdns_ufs_dme_attr_val[6]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_LOCALBUFFERSPACE), + &host->cdns_ufs_dme_attr_val[7]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_PEERBUFFERSPACE), + &host->cdns_ufs_dme_attr_val[8]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_CREDITSTOSEND), + &host->cdns_ufs_dme_attr_val[9]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_CPORTMODE), + &host->cdns_ufs_dme_attr_val[10]); + ufshcd_dme_get(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), + &host->cdns_ufs_dme_attr_val[11]); +} + +/** + * cdns_ufs_set_l4_attr - set L4 attributes on local side + * @hba: per adapter instance + * + */ +static void cdns_ufs_set_l4_attr(struct ufs_hba *hba) +{ + struct cdns_ufs_host *host = ufshcd_get_variant(hba); + + ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 0); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERDEVICEID), + host->cdns_ufs_dme_attr_val[0]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERCPORTID), + host->cdns_ufs_dme_attr_val[1]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_TRAFFICCLASS), + host->cdns_ufs_dme_attr_val[2]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_PROTOCOLID), + host->cdns_ufs_dme_attr_val[3]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTFLAGS), + host->cdns_ufs_dme_attr_val[4]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_TXTOKENVALUE), + host->cdns_ufs_dme_attr_val[5]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_RXTOKENVALUE), + host->cdns_ufs_dme_attr_val[6]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_LOCALBUFFERSPACE), + host->cdns_ufs_dme_attr_val[7]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERBUFFERSPACE), + host->cdns_ufs_dme_attr_val[8]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_CREDITSTOSEND), + host->cdns_ufs_dme_attr_val[9]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTMODE), + host->cdns_ufs_dme_attr_val[10]); + ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), + host->cdns_ufs_dme_attr_val[11]); +} /** * Sets HCLKDIV register value based on the core_clk @@ -77,6 +156,22 @@ static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba, return cdns_ufs_set_hclkdiv(hba); } +/** + * Called around hibern8 enter/exit. + * @hba: host controller instance + * @cmd: UIC Command + * @status: notify stage (pre, post change) + * + */ +static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd, + enum ufs_notify_change_status status) +{ + if (status == PRE_CHANGE && cmd == UIC_CMD_DME_HIBER_ENTER) + cdns_ufs_get_l4_attr(hba); + if (status == POST_CHANGE && cmd == UIC_CMD_DME_HIBER_EXIT) + cdns_ufs_set_l4_attr(hba); +} + /** * Called before and after Link startup is carried out. * @hba: host controller instance @@ -117,6 +212,14 @@ static int cdns_ufs_link_startup_notify(struct ufs_hba *hba, static int cdns_ufs_init(struct ufs_hba *hba) { int status = 0; + struct cdns_ufs_host *host; + struct device *dev = hba->dev; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + + if (!host) + return -ENOMEM; + ufshcd_set_variant(hba, host); if (hba->vops && hba->vops->phy_initialization) status = hba->vops->phy_initialization(hba); @@ -144,8 +247,10 @@ static int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba) static const struct ufs_hba_variant_ops cdns_ufs_pltfm_hba_vops = { .name = "cdns-ufs-pltfm", + .init = cdns_ufs_init, .hce_enable_notify = cdns_ufs_hce_enable_notify, .link_startup_notify = cdns_ufs_link_startup_notify, + .hibern8_notify = cdns_ufs_hibern8_notify, }; static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { @@ -154,6 +259,7 @@ static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { .hce_enable_notify = cdns_ufs_hce_enable_notify, .link_startup_notify = cdns_ufs_link_startup_notify, .phy_initialization = cdns_ufs_m31_16nm_phy_initialization, + .hibern8_notify = cdns_ufs_hibern8_notify, }; static const struct of_device_id cdns_ufs_of_match[] = { -- cgit v1.2.3 From bb14dd1564c90d333f51e69dd6fc880b8233ce11 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Dec 2019 13:48:28 +0300 Subject: scsi: ufs: Unlock on a couple error paths We introduced a few new error paths, but we can't return directly, we first have to unlock "hba->clk_scaling_lock" first. Fixes: a276c19e3e98 ("scsi: ufs: Avoid busy-waiting by eliminating tag conflicts") Link: https://lore.kernel.org/r/20191213104828.7i64cpoof26rc4fw@kili.mountain Reviewed-by: Bart Van Assche Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e5cd57e68c46..bf981f0ea74c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2617,8 +2617,10 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, * the maximum wait time is bounded by SCSI request timeout. */ req = blk_get_request(q, REQ_OP_DRV_OUT, 0); - if (IS_ERR(req)) - return PTR_ERR(req); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto out_unlock; + } tag = req->tag; WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag)); @@ -2646,6 +2648,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, out_put_tag: blk_put_request(req); +out_unlock: up_read(&hba->clk_scaling_lock); return err; } @@ -5854,8 +5857,10 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, down_read(&hba->clk_scaling_lock); req = blk_get_request(q, REQ_OP_DRV_OUT, 0); - if (IS_ERR(req)) - return PTR_ERR(req); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto out_unlock; + } tag = req->tag; WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag)); @@ -5934,6 +5939,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, } blk_put_request(req); +out_unlock: up_read(&hba->clk_scaling_lock); return err; } -- cgit v1.2.3 From dc30c9e6d67f9edb02d543e1f213f3250bfa3a78 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Dec 2019 13:49:35 +0300 Subject: scsi: ufs: Simplify a condition We know that "check_for_bkops" is non-zero on this side of the || because it was checked on the other side. Link: https://lore.kernel.org/r/20191213104935.wgpq2epaz6zh5zus@kili.mountain Reviewed-by: Bart Van Assche Reviewed-by: Avri Altman Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index bf981f0ea74c..c299c5feaf1a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7684,8 +7684,7 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, * turning off the link would also turn off the device. */ else if ((req_link_state == UIC_LINK_OFF_STATE) && - (!check_for_bkops || (check_for_bkops && - !hba->auto_bkops_enabled))) { + (!check_for_bkops || !hba->auto_bkops_enabled)) { /* * Let's make sure that link is in low power mode, we are doing * this currently by putting the link in Hibern8. Otherway to -- cgit v1.2.3 From dcb6cec508277807f57422dc07084e3a78890946 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Sat, 7 Dec 2019 20:22:00 +0800 Subject: scsi: ufs: disable irq before disabling clocks During suspend flow, interrupt shall be disabled before disabling clocks to avoid potential system hang due to accessing host registers after host clocks are disabled. For example, if an interrupt comes with IRQF_IRQPOLL flag configured with the misrouted interrupt recovery feature enabled, ufshcd ISR may be triggered even if nothing shall be done for UFS. In this case, system hang may happen if UFS interrupt status register is accessed with host clocks disabled. Link: https://lore.kernel.org/r/1575721321-8071-2-git-send-email-stanley.chu@mediatek.com Reviewed-by: Avri Altman Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c299c5feaf1a..f55cf036c3fe 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7890,6 +7890,11 @@ disable_clks: ret = ufshcd_vops_suspend(hba, pm_op); if (ret) goto set_link_active; + /* + * Disable the host irq as host controller as there won't be any + * host controller transaction expected till resume. + */ + ufshcd_disable_irq(hba); if (!ufshcd_is_link_active(hba)) ufshcd_setup_clocks(hba, false); @@ -7899,11 +7904,7 @@ disable_clks: hba->clk_gating.state = CLKS_OFF; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); - /* - * Disable the host irq as host controller as there won't be any - * host controller transaction expected till resume. - */ - ufshcd_disable_irq(hba); + /* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm(hba); goto out; -- cgit v1.2.3 From 8b0bbf002a1eb9074ab770e21cd454137c76c106 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Sat, 7 Dec 2019 20:22:01 +0800 Subject: scsi: ufs: disable interrupt during clock-gating Similar to suspend, ufshcd interrupt can be disabled since there won't be any host controller transaction expected till clocks ungated. Link: https://lore.kernel.org/r/1575721321-8071-3-git-send-email-stanley.chu@mediatek.com Reviewed-by: Asutosh Das Reviewed-by: Avri Altman Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index f55cf036c3fe..a6936bebb513 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1466,6 +1466,8 @@ static void ufshcd_ungate_work(struct work_struct *work) spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_setup_clocks(hba, true); + ufshcd_enable_irq(hba); + /* Exit from hibern8 */ if (ufshcd_can_hibern8_during_gating(hba)) { /* Prevent gating in this path */ @@ -1612,6 +1614,8 @@ static void ufshcd_gate_work(struct work_struct *work) ufshcd_set_link_hibern8(hba); } + ufshcd_disable_irq(hba); + if (!ufshcd_is_link_active(hba)) ufshcd_setup_clocks(hba, false); else -- cgit v1.2.3 From 0786669c31c91549bd910a9f90553491fc3f256a Mon Sep 17 00:00:00 2001 From: Sheeba B Date: Mon, 16 Dec 2019 11:17:12 +0100 Subject: scsi: ufs: Power off hook for Cadence UFS driver Attach power off hook to Cadence UFS driver. Link: https://lore.kernel.org/r/1576491432-631-1-git-send-email-sheebab@cadence.com Reviewed-by: Avri Altman Reviewed-by: Alim Akhtar Signed-off-by: Sheeba B Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/cdns-pltfrm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index 1c80f9633da6..56a6a1ed5ec2 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -325,6 +325,7 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = { static struct platform_driver cdns_ufs_pltfrm_driver = { .probe = cdns_ufs_pltfrm_probe, .remove = cdns_ufs_pltfrm_remove, + .shutdown = ufshcd_pltfrm_shutdown, .driver = { .name = "cdns-ufshcd", .pm = &cdns_ufs_dev_pm_ops, -- cgit v1.2.3 From 43d23b94e5e863909b397c8b962f268ea2656ee4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 9 Dec 2019 09:42:05 -0800 Subject: scsi: core: Fix a compiler warning triggered by the SCSI logging code This patch fixes the following compiler warning: In file included from drivers/scsi/scsi_error.c:46: drivers/scsi/scsi_error.c: In function 'scsi_eh_target_reset': drivers/scsi/scsi_logging.h:65:81: warning: suggest braces around empty body in an 'if' statement [-Wempty-body] 65 | LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD); | ^ drivers/scsi/scsi_error.c:1562:4: note: in expansion of macro 'SCSI_LOG_ERROR_RECOVERY' 1562 | SCSI_LOG_ERROR_RECOVERY(3, | ^~~~~~~~~~~~~~~~~~~~~~~ Link: https://lore.kernel.org/r/20191209174205.190025-1-bvanassche@acm.org Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_logging.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_logging.h b/drivers/scsi/scsi_logging.h index 836185de28c4..3df877886119 100644 --- a/drivers/scsi/scsi_logging.h +++ b/drivers/scsi/scsi_logging.h @@ -53,7 +53,7 @@ do { \ } while (0) #else #define SCSI_LOG_LEVEL(SHIFT, BITS) 0 -#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) +#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) do { } while (0) #endif /* CONFIG_SCSI_LOGGING */ /* -- cgit v1.2.3 From 08fcc87bd0df7be62752b041592db414ba2a4f04 Mon Sep 17 00:00:00 2001 From: Chen Zhou Date: Thu, 12 Dec 2019 10:35:56 +0800 Subject: scsi: sym53c8xx: fix typos in comments Fix the typo "GPOI" -> "GPIO" in comment. Link: https://lore.kernel.org/r/20191212023556.72618-1-chenzhou10@huawei.com Signed-off-by: Chen Zhou Signed-off-by: Martin K. Petersen --- drivers/scsi/sym53c8xx_2/sym_nvram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c index 9dc17f1288f9..d37e2a69136a 100644 --- a/drivers/scsi/sym53c8xx_2/sym_nvram.c +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c @@ -227,7 +227